第5章 给Agent一个好脑子
第4章讲了Agent是什么——一个能感知、规划、行动、反思的聪明程序。那这个程序最核心的"聪明"从哪来?这一章,我们聊聊Agent的"大脑"——大语言模型(LLM)。不用担心数学公式,我们只讲"它怎么想事情"和"你怎么跟它说话让它变聪明"。
5.1 LLM是怎么"想事情"的?
5.1.1 别被"大语言模型"这名字吓到
很多人一听"大语言模型"就觉得:肯定要学数学、神经网络、梯度下降……
不需要。
你开车不需要懂发动机原理,你只需要知道踩油门会加速、打方向盘会转弯。用LLM也一样——你不用懂Transformer架构,你只需要知道:
LLM本质上就是一个"接话高手"。你给它一段文字,它预测下一个最可能出现的词,一个词一个词接下去,直到把整段话说完。
是不是比你想的简单?它就是一直问自己"根据前文,下一个词大概率是什么",然后挑最可能的那个写上去。
5.1.2 那它为什么能"变聪明"?
"接话"听起来很简单,但当LLM读过了几乎整个互联网的文字之后,它"接"出来的话就变得非常有道理了。
比如你输入"帮我写一个Python函数,输入一个列表,返回它的中位数",LLM能"接"出正确的代码——因为它在训练时见过太多类似的问答了。
关键是:LLM的"知识"截止到它的训练数据日期。它不知道今天的新闻,不知道你公司的内部文件。这就是为什么Agent需要RAG(第7章)和工具调用(第6章)——补上"实时信息"这块短板。
5.2 教LLM学会新任务
5.2.1 零样本:直接问,不给例题
最简单的用法——直接问。
你:"把下面这句话翻译成英文:今天天气真好。"
LLM:"The weather is really nice today."你没有给它任何例子,它照样能做。这叫做零样本(Zero-shot)。LLM在训练时已经见过足够的翻译数据,所以不需要你教。
但零样本的极限也很明显——遇到复杂任务就懵了。
你:"分析这段代码的时间复杂度和空间复杂度,并给出优化建议。"
LLM:(给了一个看起来对但其实有漏洞的答案)5.2.2 少样本:给几个例子,让它学着来
当你发现零样本搞不定的时候,给它看几个例子。这就是少样本(Few-shot)。
零样本——直接问:
你:把下面的用户反馈分类为"好评"、"中评"、"差评"。
反馈:"物流太慢了,东西还行吧。"
LLM:差评(猜错了——其实偏中评)少样本——先给例子再看:
你:请参考以下例子对反馈分类:
例子1:"太棒了,下次还来" → 好评
例子2:"一般般,没啥特别" → 中评
例子3:"质量太差,不会再买" → 差评
现在分类:"物流太慢了,东西还行吧。"
LLM:中评(对了!因为有例子参考)5.2.3 少样本的实战技巧
技巧1:例子要典型。 如果你要让LLM识别"紧急程度",给的例子要覆盖"紧急"、"普通"、"不急"三种情况,别全给"紧急"的。
技巧2:例子要简短。 别把一个完整项目文档当例子——LLM的注意力会分散。3-5个简短例子效果最好。
技巧3:例子放最后。 把最重要的例子放在最后——LLM对离它最近的上下文最敏感。
5.3 思维链与推理增强
5.3.1 "一步一步想"的魔力
LLM最强的地方不是"给答案",而是"给推理过程"。当你要求它"一步一步想",它的准确率会大幅提升。
不加思维链——直接问:
你:一个水果摊有苹果25个,卖出了8个,又进了15个,现在有多少个?
LLM:32个(错了!应该是32吗?25-8+15=32,这个其实是对的,但我们换个复杂的)换个复杂点的:
你:小明有3个苹果,小红有2倍于小明的苹果,小刚有小红一半的苹果。三人一共有多少个?
LLM:10个(错了!应该是3+6+3=12)加思维链——让它写过程:
你:一步步算:小明有3个。小红是小明的2倍=6个。小刚是小红的一半=3个。总共=3+6+3=
LLM:12个(对了!因为它一步一步来,没有跳步)这就是思维链(Chain of Thought,CoT)——你不需要教它新知识,只需要让它"别急着回答,先写草稿"。
5.3.2 怎么让LLM用思维链
最简单的办法:在Prompt里加一句。
请一步一步思考,先写出推理过程,再给出最终答案。这句话适用于几乎所有的推理任务——数学、逻辑、编程调试、决策分析。
进阶用法:直接给它看一个有思维链的例子。
例子:
问:一个班有20个男生,女生是男生的1.5倍,全班多少人?
推理:女生=20×1.5=30人。全班=20+30=50人。
答案:50人。
现在回答:
问:一个公司有80个员工,40%是工程师,其中一半是后端,后端有多少人?5.3.3 思维链的边界
思维链不是万能的。它能让LLM更准确地推理,但如果LLM本身的知识就是错的,思维链只会让它"更自信地犯错"。
所以当你用LLM做Agent的"大脑"时,不能全信它的推理——需要有工具验证(第6章)、需要给它查资料(第7章)。
5.4 好的Prompt是写出来的,不是想出来的
5.4.1 Prompt就是Agent的"任务说明书"
很多人把Prompt当成"随便写一句指令"。其实Prompt是你在跟一个超级聪明但完全没有常识的实习生沟通——你说的每一句话,都会影响它的输出质量。
差Prompt:
你:帮我写个函数。(太模糊)
LLM:什么语言?什么功能?什么参数?好Prompt:
你:用Python写一个函数,输入一个整数列表,返回其中位数。
要求:不要用numpy。如果列表为空返回None。
LLM:(给出正确的代码)5.4.2 Prompt设计的四条铁律
写 Prompt 就像给新员工下任务——说清楚比说得多重要。从"帮我看看代码"到"你是Python专家,请审查以下代码的安全问题",效果天差地别:
铁律一:角色要明确。 告诉LLM"你是谁"。
你是一个Python代码审查专家。请审查以下代码的问题。vs
帮我看看这段代码有什么问题。前者让LLM进入"专家模式",输出质量明显更高。
铁律二:任务要具体。 "帮我写"不如"帮我写一个函数,输入X返回Y"。
铁律三:格式要限定。 如果你需要JSON,直接说"请以JSON格式返回"。
铁律四:给反例。 告诉LLM"不要做什么"往往和"要做什么"一样重要。
请写一个友好的回复。不要道歉,不要问"我还能帮你什么",不要超过50个字。5.4.3 Agent中的Prompt实战
在Agent系统中,Prompt通常会被写成一个模板。因为同样的任务逻辑,用户每次输入的内容不同。
python
# Agent的意图识别Prompt模板
intent_prompt = """
你是一个客服意图识别助手。
根据用户输入,判断意图是以下哪种:查询订单、申请退款、投诉、其他。
用户输入:{user_message}
请只返回意图名称,不要加任何解释。
"""这个模板在不同用户输入下反复使用——{user_message} 每次被替换成用户实际说的话。
5.5 用 LangChain 管理 Prompt 与 Chain
前面我们手写了 Prompt 模板,但真正开发 Agent 时,Prompt 不是一次性用完就扔的——你需要动态替换变量、组合多个 Prompt、把 LLM 的输出解析成结构化数据。这时候,代码框架就该登场了。
LangChain 为 Prompt 和 Chain 的管理提供了一套完整的工具链。我们不重复讲概念,直接看 LangChain 特有的能力。
5.5.1 Few-Shot 也能写成代码
5.2 节讲了 Few-shot 的概念——给 LLM 几个例子让它照着学。但在代码里,你不可能每次都手动拼一个带例子的 Prompt 字符串。LangChain 提供了 FewShotPromptTemplate,把"例子管理"和"模板拼接"解耦开:
python
from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
# 管理你的例子库(可以随时增删,不用改主模板)
examples = [
{"word": "开心", "antonym": "伤心"},
{"word": "高大", "antonym": "矮小"},
]
# 定义每个例子怎么展示
example_prompt = PromptTemplate.from_template("词语: {word}\n反义词: {antonym}")
# 主模板:prefix 放前面,examples 自动插入,suffix 放后面
prompt = FewShotPromptTemplate(
examples=examples,
example_prompt=example_prompt,
prefix="请给出下列词语的反义词:",
suffix="词语: {input}\n反义词:",
input_variables=["input"]
)
# 实际使用时,只需传用户输入
result = prompt.invoke({"input": "快速"})
print(result.to_string())
# 请给出下列词语的反义词:
# 词语: 开心
# 反义词: 伤心
# 词语: 高大
# 反义词: 矮小
#
# 词语: 快速
# 反义词:这比你每次手动拼字符串优雅得多。例子库可以存在数据库里、可以从配置文件加载——模板本身保持不变。
5.5.2 Chat Prompt:区分"谁在说话"
前面我们用简单的字符串模板就够了,但在多轮对话和 Agent 场景中,你需要区分系统指令、用户输入、AI 回复。LangChain 的 ChatPromptTemplate 用角色标签来组织这些消息:
python
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
("system", "你是一位专业的{subject}老师。"), # 系统指令
("human", "请解释:{concept}"), # 用户输入
])
messages = prompt.invoke({
"subject": "物理学",
"concept": "量子纠缠"
})LLM 拿到的不再是一串文字,而是有结构的信息——它知道第一条是"你的角色设定",第二条才是"用户要你回答的问题"。这就是 SystemMessage / HumanMessage 的分工。
5.5.3 输出解析器:别让 LLM 说废话
Prompt 设计中最头疼的问题之一:LLM 的输出格式不可控。
你让它"以 JSON 返回",它可能会在前面加一句"好的,以下是 JSON 格式的结果:",然后才是 JSON。你的解析器就崩了。
Output Parser 就是来解决这个问题的——它让 LLM 直接吐出结构化数据。
StrOutputParser:最简单的,把输出当纯文本,自动去掉多余空白和标记。
JsonOutputParser:配合 Pydantic 模型,让 LLM 输出合法的 JSON(dict):
python
from langchain_core.output_parsers import JsonOutputParser
from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field
# 用 Pydantic 定义你期望的输出结构
class Joke(BaseModel):
setup: str = Field(description="笑话的铺垫")
punchline: str = Field(description="笑话的笑点")
# 创建解析器,告诉它"我要这种结构"
parser = JsonOutputParser(pydantic_object=Joke)
# 连起来:prompt → LLM → parser
chain = prompt | llm | parser
result = chain.invoke({"topic": "程序员"})
print(result) # {"setup": "为什么程序员...", "punchline": "因为..."}
# result 已经是正经的 dict,可以直接 .get("punchline")Parser 拿到的是 Python dict,不再是"像 JSON 的字符串"。你的代码再也不用写 json.loads() + try/except 了。
注意:对于复杂结构,Parser 依赖 LLM 正确遵循格式指令。关键业务场景建议加一层校验。
5.5.4 LCEL:一个竖线串起一切
前面你已经看到了 | 管道符。这是 LangChain 最核心的设计——LCEL(LangChain Expression Language)。
python
chain = prompt | llm | parser
result = chain.invoke({"topic": "程序员"})这一行的含义是:把用户输入填进模板 → 发给 LLM → 把 LLM 的返回交给解析器。每个组件都可以单独替换、单独测试。
两个 Chain 还能串起来——上一个的输出成为下一个的输入:
python
# Chain1: 翻译成英文
translate_chain = (
ChatPromptTemplate.from_template("翻译成英文:{text}")
| llm | StrOutputParser()
)
# Chain2: 一句话总结
summarize_chain = (
ChatPromptTemplate.from_template("一句话总结:{text}")
| llm | StrOutputParser()
)
# 串联:先翻译,再总结
final_chain = {"translation": translate_chain} | summarize_chain
result = final_chain.invoke({"text": "今天天气真好"})更灵活的是路由链——根据输入内容,动态选择走哪条处理路径:
python
# 定义两条分支
translate_chain = (ChatPromptTemplate.from_template("翻译:{text}") | llm | StrOutputParser())
qa_chain = (ChatPromptTemplate.from_template("问答:{text}") | llm | StrOutputParser())
# 路由器:让 LLM 判断该走哪条
router = ChatPromptTemplate.from_template(
"判断以下输入是翻译请求还是问答请求,只回复 'translate' 或 'qa':\n输入:{text}"
) | llm | StrOutputParser()
def route(text):
choice = router.invoke({"text": text}).strip().lower()
if "translate" in choice:
return translate_chain.invoke({"text": text})
return qa_chain.invoke({"text": text})这种组件化的设计思路贯穿 LangChain 的始终——每个零件都是可替换的,串联方式却始终一样。就像乐高,积木不同,但连接方式是统一的。
一句话总结这一节:LangChain 帮你把 Prompt 从"一次性拼字符串"升级到"可复用、可组合、可解析的组件系统"。你不再跟字符串搏斗,而是在拼积木。
5.6 本章小结
这一章我们搞清楚了Agent"大脑"的运作方式:
- LLM就是接话高手:一个词一个词地预测下一个词。但因为见得多,"接"出来的话显得很聪明。
- 少样本学习:给LLM几个例子,它就能做复杂任务。例子要典型、简短、重要放最后。
- 思维链:让LLM"一步一步想",准确率暴涨。原理很简单——别让它跳步。
- Prompt设计:角色明确、任务具体、格式限定、给反例。Agent的Prompt就是它的"任务说明书"。
- LangChain Prompt 管理:FewShotPromptTemplate 管理示例库、ChatPromptTemplate 组合消息模板、OutputParser 解析结构化输出、LCEL 管道串联——代码框架让 Prompt 工程从"手写字符串"升级为"工程化管理"。
记住一句话:LLM是你见过最聪明也最没常识的实习生——你交代得越清楚,它做得越好。
✅ 知识点检查
学完这一章,试试回答这几个问题:
- [ ] LLM"接话"的过程是怎样的?为什么它看起来像在"思考"?
- [ ] 零样本和少样本的区别是什么?什么情况下用少样本?
- [ ] 思维链为什么能提高LLM的推理准确率?怎么在Prompt里触发它?
- [ ] Prompt设计的四条铁律分别是什么?
- [ ] LangChain 的 FewShotPromptTemplate 和 LCEL 管道分别解决什么问题?
📚 延伸阅读
- OpenAI Prompt Engineering Guide:https://platform.openai.com/docs/guides/prompt-engineering
- 《Chain-of-Thought Prompting Elicits Reasoning in Large Language Models》— Google Research
- 本书配套源码:关注公众号「图解AI系列」免费领取
🎯 下一章预告
第6章,Agent光有脑子还不够——
"光说不练假把式。让Agent学会调用工具,它才能真正帮你干活。"

