前言
之前学了 ReAct 和 Plan and Execute 两种 Agent 中的设计范式,那么除了这两种还有别的范式吗?
我们知道 LLM 最开始以 Chat 的形式风靡全世界,那么既然他可以和人类对话。可不可以让他就某个问题的答案进行自问自答来增强答案准确性呢?哈哈没错,答案是肯定的。他就是我们今天要看的 Self-Ask 回路验证
定义
自问自答(Self-Ask) 范式允许大模型对自己提出问题并回答,来增强对问题的理解以提高回答质量。
-
本质:"思考-验证-再行动"
-
核心流程-
- 自我提问(Self-Ask) :当Agent接到一个复杂问题(例如:"珠穆朗玛峰的高度和《三体》的作者有关联吗?"),它不会直接回答,而是先自主拆解。它会生成一个或多个子问题,例如:"1. 珠穆朗玛峰的精确高度是多少? 2. 《三体》的作者是谁?"
-
执行与验证(Act & Verify) :Agent会通过调用工具 (如联网搜索)来寻找每个子问题的答案,同时评估答案的可信度 (来源是否权威?信息是否一致?是否与已知事实冲突?)。这一步是防御"幻觉"的核心。
-
综合与迭代(Synthesize & Iterate) :基于已验证子答案,Agent尝试综合出最终答案。如果发现信息不足、矛盾或推导不出结论,它会生成新的、更精确的子问题,回到步骤1,形成回路。直到所有信息被验证且逻辑闭环,才输出最终答案。

哟,赶脚有点像之前 AdvancedRAG 提到的问题拆解,思路一致应用不同。
Coding
Prompt
我们还是尝试在 Langsmith-Hub 搜索 "Self-Ask",模板还有好几个呢,我们一般选择浏览和下载量最多的,如:hwchase17/self-ask-with-search。


vbnet
template_template = '''
Answer the following question. When needed, you can ask follow-up questions and answer them to reach the final answer. Always use English format for follow-up questions and answers:
Examples:
Question: Who lived longer, Muhammad Ali or Alan Turing?
Are follow up questions needed here: Yes.
Follow up: How old was Muhammad Ali when he died?
Intermediate answer: Muhammad Ali was 74 years old when he died.
Follow up: How old was Alan Turing when he died?
Intermediate answer: Alan Turing was 41 years old when he died.
So the final answer is: Muhammad Ali
Question: When was the founder of craigslist born?
Are follow up questions needed here: Yes.
Follow up: Who founded craigslist?
Intermediate answer: Craigslist was founded by Craig Newmark.
Follow up: When was Craig Newmark born?
Intermediate answer: Craig Newmark was born on December 6, 1952.
So the final answer is: December 6, 1952
Question: Who was George Washington's paternal grandfather?
Are follow up questions needed here: Yes.
Follow up: Who was George Washington's father?
Intermediate answer: George Washington's father was Augustine Washington.
Follow up: Who was Augustine Washington's father?
Intermediate answer: Augustine Washington's father was Lawrence Washington.
So the final answer is: Lawrence Washington
IMPORTANT:
1. ONLY use the exact format shown above
2. DO NOT include any explanations or extra text
3. DO NOT use markdown formatting like **bold**
4. ONLY output in the specified format
5. End your response with "So the final answer is: [answer]"
Question: {input}
Are follow up questions needed here: {agent_scratchpad}
'''
PromptTemplate注意事项
缘起
上述的模版是英文,执行也没问题。但是对于英语不好的筒子可能想使用中文模板,那么可以吗?我们不妨一试,修改提示词模版为中文。
ini
template_template = '''
在回答用户问题时,可以自己提出问题并回答,来增强对问题的理解以提高回答质量。
示例:
问题:谁活得更久,穆罕默德·阿里还是阿兰·图灵?
这里是否需要后续问题:是的。
追问:穆罕默德·阿里去世时几岁?
中间答案:穆罕默德·阿里去世时74岁。
追问:阿兰·图灵去世时几岁?
中间答案:阿兰·图灵去世时41岁。
最终答案:穆罕默德·阿里
用户问题: {input}
解决问题:{agent_scratchpad}
'''
开始看着好像也能正常问答。我去,怎么感觉进入死循环了,尽管得出了答案一直在死循环,直到最后程序被自动强制停止。还有点像我们传统开发里的递归死循环问题。

直捣黄龙一探究竟
那么这是为什么呢?好在 Langchain 都是开源代码,我们不妨直接查看源代码看看。经过一番追踪,最终我定位在了 self_ask.py 文件:
- 模块:
langchain_classic.agents.output_parsers.self_ask.py SelfAskOutputParser:self-ask范式定义的输出解析器

我勒个去,这是发现了什么?
- 这个解析强依赖 Prompt 硬编码中的 "Follow up:" 等字符,注意有冒号!
- 针对部分字符,如 "So the final answer is: ",末尾还有一个空格!!
注意事项
所以,我们编写中文提示词模板的时候就有的放矢了。英文模板中的关键引导词 必须保留不变:Question、Follow up、Intermediate answer、So the final answer is 等。
"Follow up:":作为 SelfAskOutputParser 中 followups 来源"So the final answer is: ": SelfAskOutputParser 中 finish_string 来源;⚠️⚠️⚠️:这里末尾还有个**【空格】**一定不能丢"Intermediate Answer": SelfAskOutputParser 中 作为 action 的调用源
那么问题来了:我们看源代码中并未依赖 Question ,为什么建议 Question 也保留呢?
- 跟其他字段对齐
- 养成良好代码习惯,后续遇到其他情况一开始我们可能并不知道哪些字段硬编码依赖,这样可以防止再出现类似问题
ini
# ✅✅✅【正确示例】✅✅✅
template_template = '''
在回答用户问题时,可以自己提出问题并回答,来增强对问题的理解以提高回答质量。
示例:
Question: 谁活得更久,穆罕默德·阿里还是阿兰·图灵?
这里是否需要后续问题:是的。
Follow up: 穆罕默德·阿里去世时几岁?
Intermediate answer: 穆罕默德·阿里去世时74岁。
Follow up: 阿兰·图灵去世时几岁?
Intermediate answer: 阿兰·图灵去世时41岁。
So the final answer is: 穆罕默德·阿里。
用户问题: {input}
解决问题:{agent_scratchpad}
'''
思考🤔
我们发现 create_self_ask_with_search_agent 又是 Langchain 0.x 时代遗留的接口。再一次印证 Langcchain 1.0 时代鼓励使用新范式是正确的。
- Langchain 0.x 早期为了快速实现和保证基础功能的确定性,牺牲了国际化和灵活性。
- Langchain 1.0 框架升级后吸取之前的经验,将一些前沿激进的技术、API还未稳定成熟的接口放在了
langchain_experimental。- 分层治理和迭代 的设计思想得到进一步体现。
核心代码
ini
tools = [TavilyAnswer(
max_results=1,
include_raw_content=True,
name="Intermediate Answer",
tavily_api_key=os.getenv("TAVILY_API_KEY"))]
agent = create_self_ask_with_search_agent(llm, tools, prompt)
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True,
handle_parsing_errors=True)
Runing
arduino
print(agent_executor.invoke({"input": "《大白鲨》和《皇家赌场》的导演都来自同一个国家吗?"}))
