从调参到编排:LLM 应用优化的范式转移

2026-04-17 25 预计阅读时间:1 分钟
来源:realpython.com AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:13 分钟

大模型应用的开发方式正在经历一次静默但深刻的转向——把精力从"怎么把模型本身训得更好"挪到了"怎么把模型周围的上下文和协作流程搭得更合理"。JetBrains 数据科学家兼 Python Advocacy Team Lead Jodie Burchell 在 Real Python Podcast 第 291 期中梳理了这股趋势:行业正从 post-training 优化走向 context engineeringmulti-agent orchestration。这不是概念炒作,而是工程团队在真实项目中踩过坑后的务实选择。

为什么 post-training 不再是主角

Post-training 指的是在基础模型之上做进一步训练——微调(fine-tuning)、RLHF、DPO 等。这套方法在 2023 年是主流叙事:你有领域数据,你微调一个模型,它就变聪明了。

现实很快给出反馈:

  • 数据门槛高:高质量标注数据的获取成本远超预期,很多团队攒了几千条就发现不够。
  • 迭代周期长:一次微调从数据准备到评估跑完,动辄数天;业务需求却要求按周迭代。
  • 效果边际递减:在通用基座模型已经很强的前提下,微调带来的增量往往不如把 prompt 和检索链路调好。

Burchell 指出,越来越多团队意识到:与其花两周微调一个模型只提升 3% 的准确率,不如花两天把 RAG 的检索策略和 prompt 结构调到位,效果可能更显著。这不是否定微调的价值,而是说在大多数应用场景里,模型本身已经不是瓶颈,上下文的组织方式才是

Context Engineering:把"喂什么"当工程问题做

Context engineering 的核心思路:模型的能力是固定的,但你给它什么信息、以什么格式、在什么时机给——这些是可以系统化优化的工程变量。

它至少覆盖三个层面:

1. 检索策略

不是"搜到文档丢给模型"就完了。你需要考虑:

  • 检索的粒度:段落级还是文档级?
  • 检索的排序:用向量相似度还是混合 BM25 + 向量?
  • 检索的过滤:要不要按元数据(时间、来源、权限)做二次筛选?

2. 上下文窗口的编排

模型窗口有限(即使 128K 也不够挥霍),放进来的内容要有结构:

  • 系统指令放在哪、用户问题放在哪、检索结果放在哪,顺序影响输出质量。
  • 长文档要做摘要压缩,而不是全文塞入。
  • 多轮对话的历史需要截断或摘要,而不是无限制堆叠。

3. Prompt 的模板化与版本管理

Prompt 不是一次性写死的文本,而是需要迭代、测试、版本控制的工程产物。把它当代码一样对待——有模板、有变量、有 A/B 测试。

下面是一个把 context engineering 落地为代码的简化示例,使用 LangChain 搭建一个带结构化检索和 prompt 模板的 RAG 链路:

# rag_context_engine.py — 最小可运行的 context engineering 示例
# 依赖: pip install langchain langchain-openai langchain-community chromadb

from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough

# 1. 构建向量库(用几条模拟文档)
docs = [
    "Python 3.12 引入了更快的 CPython 解释器,f-string 支持嵌套表达式。",
    "JetBrains 的 DataSpell 专为数据科学家设计,支持 Jupyter 和 DataFrame 可视化。",
    "LangChain 0.2 重构了核心抽象,Runnable 接口统一了链式调用。",
    "RAG 系统的检索质量取决于分块策略和嵌入模型的选择,而非仅靠向量相似度。",
]

vectorstore = Chroma.from_texts(docs, embedding=OpenAIEmbeddings())
retriever = vectorstore.as_retriever(search_kwargs={"k": 2})

# 2. 结构化 prompt 模板——明确区分指令、上下文、问题
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一名技术顾问。只根据下方【参考资料】回答问题。"
               "如果资料中没有相关信息,直接说'我不确定',不要编造。"),
    ("system", "【参考资料】\n{context}"),
    ("human", "{question}"),
])

# 3. 检索结果的格式化:编号 + 分隔,方便模型引用
def format_docs(docs):
    return "\n\n".join(f"[{i+1}] {d.page_content}" for i, d in enumerate(docs))

# 4. 组装链路
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
chain = (
    {"context": retriever | format_docs, "question": RunnablePassthrough()}
    | prompt
    | llm
    | StrOutputParser()
)

# 5. 运行
if __name__ == "__main__":
    answer = chain.invoke("RAG 系统怎么提升检索质量?")
    print(answer)

运行前把 OPENAI_API_KEY 设到环境变量。这个示例虽然小,但已经体现了 context engineering 的几个关键决策:检索数量限制为 2 条、上下文编号格式化、prompt 里显式标注参考资料边界、temperature 设 0 降低随机性。每一个都是可以单独调优的工程参数。

Multi-Agent Orchestration:让多个专长模型协作

另一个明显趋势是多智能体编排。单一 LLM 试图包揽所有任务——规划、检索、编码、审查——效果往往不稳定。更靠谱的做法是让不同 agent 各司其职,通过流程编排串联。

Burchell 在节目中提到,这种思路借鉴了软件工程中"关注点分离"的原则:一个 agent 负责检索,一个负责生成,一个负责校验,彼此之间通过消息传递协作,而不是把所有逻辑塞进一个超长 prompt。

一个典型的三 agent 流程:

Agent 职责 输入 输出
Planner 拆解任务、制定步骤 用户原始需求 步骤列表
Executor 按步骤执行(检索/生成代码) 单个步骤 + 上下文 中间结果
Reviewer 检查结果是否符合要求 Executor 输出 + 原始需求 通过/打回修改

下面用纯 Python 实现一个最小多 agent 编排框架,不依赖任何 agent 库,方便理解核心逻辑后自行扩展:

# multi_agent_orchestrator.py — 三 agent 协作的最小实现
# 依赖: pip install openai

import os
from openai import OpenAI

client = OpenAI()  # 需要设置 OPENAI_API_KEY 环境变量

def call_agent(role: str, instruction: str, input_text: str) -> str:
    """通用 agent 调用:角色 + 指令 + 输入 → 输出"""
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        temperature=0,
        messages=[
            {"role": "system", "content": f"你是{role}{instruction}"},
            {"role": "user", "content": input_text},
        ],
    )
    return response.choices[0].message.content

# --- 三个 agent 的定义 ---
PLANNER_ROLE = "任务规划师"
PLANNER_INSTR = "将用户需求拆解为 2-4 个可执行的步骤,每步一句话描述。只输出步骤列表,不加解释。"

EXECUTOR_ROLE = "执行者"
EXECUTOR_INSTR = "根据给定的步骤和上下文,完成该步骤的任务。输出简洁的结果文本。"

REVIEWER_ROLE = "审查者"
REVIEWER_INSTR = ("对比最终结果与原始需求,判断是否满足。"
                   "如果满足,输出'PASS';否则输出'FAIL: <具体原因>'。")

def orchestrate(user_request: str, max_retries: int = 2) -> str:
    """三 agent 编排主流程"""
    # Step 1: Planner 拆解任务
    steps_text = call_agent(PLANNER_ROLE, PLANNER_INSTR, user_request)
    print("=== 规划步骤 ===")
    print(steps_text)

    # Step 2: Executor 逐步执行
    context = f"原始需求: {user_request}\n步骤列表:\n{steps_text}"
    results = []
    for line in steps_text.strip().split("\n"):
        step = line.strip()
        if not step:
            continue
        result = call_agent(EXECUTOR_ROLE, EXECUTOR_INSTR,
                            f"当前步骤: {step}\n上下文: {context}")
        results.append(result)
        print(f"=== 执行 {step} ===\n{result}\n")

    # Step 3: Reviewer 审查
    final_output = "\n".join(results)
    review_input = f"原始需求: {user_request}\n最终结果:\n{final_output}"
    review = call_agent(REVIEWER_ROLE, REVIEWER_INSTR, review_input)
    print(f"=== 审查结果 ===\n{review}\n")

    # 如果审查失败且还有重试次数,重新规划
    if review.startswith("FAIL") and max_retries > 0:
        print("审查未通过,重新编排...")
        return orchestrate(
            f"{user_request}\n上次失败原因: {review}\n请调整步骤。",
            max_retries=max_retries - 1,
        )

    return final_output

if __name__ == "__main__":
    result = orchestrate("写一个 Python 函数,从 CSV 文件中筛选出金额大于 1000 的记录并按日期排序。")
    print("=== 最终输出 ===")
    print(result)

这个示例的关键设计点:

  • 每个 agent 有独立的角色和指令,职责边界清晰。
  • Reviewer 可以打回结果,触发重新规划——这是单 agent prompt 很难做到的闭环反馈。
  • max_retries 控制重试次数,防止无限循环。

实际项目中,你会把每个 agent 的指令做得更具体,可能给 Executor 加检索工具,给 Reviewer 加规则校验函数。但骨架就是这个。

落地前的几个务实判断

在把 context engineering 和多 agent 编排引入项目之前,有几件事值得先想清楚:

先确认瓶颈在哪。 如果你的应用连 prompt 都没调好、检索结果全是噪音,上多 agent 只会增加复杂度。先用单 agent + 结构化 prompt 把基线跑稳,再考虑拆分。

微调不是废了,而是退到特定场景。 当你需要模型输出格式高度固定(比如特定领域的 JSON schema)、或者基座模型在某类任务上确实能力不足,微调仍然是最直接的手段。只是它不再是一上来就做的默认选项。

多 agent 的编排成本是真实的。 每个 agent 调用都是一次 API 请求,三 agent 流程至少三次调用,加上重试可能五到八次。延迟和费用都要算进去。对于简单任务,单 agent + 好上下文往往更划算。

可观测性要提前建。 多 agent 流程出了问题,调试难度远高于单 prompt。从第一天就给每个 agent 的输入输出加日志,否则两周后你会完全不知道哪个环节在拖后腿。


LLM 应用优化正在从"炼模型"转向"搭管线"。Context engineering 让你把喂给模型的信息当工程参数来调;多 agent 编排让你把任务拆给专长角色来协作。两者都不是银弹,但它们代表了一种更可控、更可迭代的工作方式——而这正是工程团队最需要的。


相关推荐