LangChain v1Note 02
第 1 章:Prompt 与消息模板
学习目标
学习目标
用 ChatPromptTemplate 把稳定指令、对话历史和本次问题组合为消息列表,而不是在每个节点手写 f-string。
核心机制
ChatPromptTemplate 是一个 Runnable:输入变量字典,输出可交给 chat model 的 ChatPromptValue。from_messages 接受角色和模板;MessagesPlaceholder 专门插入已有 HumanMessage、AIMessage、ToolMessage 列表;partial 预填不会随调用变化的变量。
prompt = ChatPromptTemplate.from_messages([
("system", "你面向 {audience} 回答。"),
MessagesPlaceholder("history", optional=True),
("human", "{question}"),
]).partial(audience="Python 初学者")
数据流是 dict -> ChatPromptValue(messages) -> AIMessage。变量缺失会在格式化阶段报错;placeholder 的 optional=True 只适用于确实允许没有历史的场景。
与当前项目的关系
src/open_deep_research/prompts.py 目前存放普通字符串模板,节点用 .format(...) 后再创建 HumanMessage/SystemMessage。这是可行的,但当模板要混入多轮消息、工具消息或复用 partial 变量时,ChatPromptTemplate 更不易漏角色或漏变量。不要把 Runtime.context.api_keys、token、完整用户档案放入模板变量。
最小真实调用
uv run python docs/langchain/examples/01_prompt_templates.py
它调用一次模型,验证 history 被保留为消息、audience/style 被 partial 预填,并通过 StrOutputParser 将最终 AIMessage.content 转成字符串。
常见误区
- 把
MessagesPlaceholder当字符串插槽:它应接收消息序列,不能直接接未序列化的工具结果 dict。 - 把所有用户资料拼进 system prompt:只传模型回答需要的脱敏字段;身份和凭据仍在
Runtime.context。 - 把模板当安全边界:模板只格式化数据,不能自动防 prompt injection 或数据泄露。
官方参考:ChatPromptTemplate。
相关资源
查看示例代码:docs/langchain/examples/01_prompt_templates.py
"""Chapter 1: prompt templates and message placeholders.""" import asyncio from dotenv import load_dotenv from langchain.chat_models import init_chat_model from langchain_core.messages import AIMessage, HumanMessage from langchain_core.output_parsers import StrOutputParser from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from open_deep_research.configuration import Configuration load_dotenv() async def main(): settings = Configuration.from_env() prompt = ChatPromptTemplate.from_messages( [ ("system", "你是面向 {audience} 的 LangChain 助手。回答要 {style}。"), MessagesPlaceholder("history", optional=True), ("human", "{question}"), ] ).partial(audience="Python 初学者", style="简洁且准确") chain = prompt | init_chat_model( model=settings.research_model, max_tokens=120, ) | StrOutputParser() answer = await chain.ainvoke( { "history": [ HumanMessage(content="我在学习 LangChain。"), AIMessage(content="好的。"), ], "question": "ChatPromptTemplate 的作用是什么?", } ) print("模型回答: " + answer) if __name__ == "__main__": asyncio.run(main())