在上一篇中,我们已经掌握了如何用 LangChain 和 LangGraph 快速搭建一个具备多轮记忆能力的测试辅助聊天机器人。但对于追求专业性和高质量交互体验的测试工程师来说,光会“聊天”还远远不够。
如何让机器人说话更贴合业务?如何优雅控制上下文长度?如何流畅输出长文本? 这些实用需求,都能通过 LangChain 的 Prompt 模板、历史管理与流式输出能力轻松搞定。
本篇带你进阶:让你的测试智能助手不仅会“记”,还能“说得专业、聊得流畅”。
一、Prompt模板:让机器人说话有风格、有规范
1. Prompt模板是什么?
Prompt Template(提示模板)就是用来把用户的原始输入,转成 LLM 更好理解、更能按你预期表达的格式。
比如:你希望机器人说话像海盗,可以这样写👇
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
prompt_template = ChatPromptTemplate.from_messages([
(
"system",
"你是一个私人助手,请尽你所能帮我解决我的疑问吧",
),
MessagesPlaceholder(variable_name="messages")
])
- system:定义机器人说话的风格、定位、行为规范。
- MessagesPlaceholder:占位符,传入历史消息(对话上下文)。
2. 应用到多轮对话
把 prompt_template 应用到对话链条里:
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import START, MessagesState, StateGraph
# 定义一个graph
workflow = StateGraph(state_schema=MessagesState)
def call_model(state: MessagesState):
prompt = prompt_template.invoke(state)
response = model.invoke(prompt)
return {"messages": response}
workflow.add_edge(START, "model")
workflow.add_node("model", call_model)
# 记忆保存在内存中
memory = MemorySaver()
app = workflow.compile(checkpointer=memory)
效果:
问“Hi! I’m Jim.”,机器人会用“海盗腔”回答你。
config = {"configurable": {"thread_id": "test_345"}}
query = "Hi I am Jim"
input_messages = [HumanMessage(query)]
output = app.invoke({"messages": input_messages}, config)
output["messages"][-1].pretty_print()
================================== Ai Message ==================================
Hi Jim! 👋 How can I assist you today? Whether you need help with a task, have questions, or just want to chat—I'm here for you. Let me know what's on your mind! 😊
query = "What is my name"
input_messages = [HumanMessage(query)]
output = app.invoke({"messages": input_messages}, config)
output["messages"][-1].pretty_print()
================================== Ai Message ==================================
Your name is **Jim**! 😊 You introduced yourself at the beginning with "Hi I am Jim." Unless you'd like me to call you something else—just let me know!
How can I help you today, Jim? 🚀
二、让Prompt更灵活:动态参数定制
实际业务中,你可能需要让机器人支持多语言、不同角色等需求。Prompt模板可以用变量动态填充!
prompt_template = ChatPromptTemplate.from_messages([(
"system",
"你是一名资深的Python测试开发工程师,生成代码默认以{language}",
),
MessagesPlaceholder(variable_name="messages")
])
- 这里
{language}
就是动态参数,比如你传入 “python”,回答就会以python代码输出!
1. 状态管理:支持多参数
要让多轮对话记住“语言”参数,只需把 state 扩展一下:
class State(TypedDict):
messages: Annotated[Sequence[BaseMessage], add_messages]
language: str
- messages:对话历史
- language:当前对话的语言
再调用时,直接传入:
config = {"configurable": {"thread_id": "abc456"}}
query = "给我生成一个冒泡排序的代码"
language = "Python"
input_messages = [HumanMessage(query)]
output = app.invoke(
{"messages": input_messages, "language": language},
config,
)
output["messages"][-1].pretty_print()
================================== Ai Message ==================================
以下是一个标准的冒泡排序算法的Python实现:
```python
def bubble_sort(arr):
"""
冒泡排序算法实现
参数:
arr (list): 待排序的列表
返回:
list: 排序后的列表
"""
n = len(arr)
# 遍历所有数组元素
for i in range(n):
# 最后i个元素已经是排好序的
for j in range(0, n-i-1):
# 如果当前元素比下一个元素大,则交换它们
if arr[j] > arr[j+1]:
arr[j], arr[j+1] = arr[j+1], arr[j]
return arr
# 测试代码
if __name__ == "__main__":
test_list = [64, 34, 25, 12, 22, 11, 90]
print("排序前:", test_list)
sorted_list = bubble_sort(test_list)
print("排序后:", sorted_list)
输出结果:
排序前: [64, 34, 25, 12, 22, 11, 90]
排序后: [11, 12, 22, 25, 34, 64, 90]
这个实现包含了:
- 基本的冒泡排序算法
- 详细的注释说明
- 测试用例
- 时间复杂度为O(n²)
如果需要优化版本(例如添加提前终止标志),可以这样修改:
def optimized_bubble_sort(arr):
n = len(arr)
for i in range(n):
swapped = False
for j in range(0, n-i-1):
if arr[j] > arr[j+1]:
arr[j], arr[j+1] = arr[j+1], arr[j]
swapped = True
# 如果没有发生交换,说明已经有序
if not swapped:
break
return arr
**下次只传消息,语言仍然记得!**
这意味着你可以灵活定制机器人的风格、输出格式、用例详细度等——只需把这些作为state参数即可。
---
## 三、上下文历史管理:让回复始终“刚刚好”
### 为什么要裁剪历史?
LLM 的上下文窗口是有限的(比如 GPT-4o 8k/32k tokens),如果对话历史无限增长,模型会“超载”,导致:
- 消耗大量 API 费用
- 超窗口后无法记住早期内容
### 怎么裁剪?一句代码就够!
```python
from langchain_core.messages import SystemMessage, trim_messages
from langchain_core.messages import AIMessage
import tiktoken
from typing import Tuple
from langchain_openai import ChatOpenAI
class ChatOpenAIForCounter(ChatOpenAI):
def _get_enccoding_model(str) -> Tuple[str, tiktoken.Encoding]:
model = "gpt-3.5-turbo"
return model, tiktoken.encoding_for_model(model)
trim_model = ChatOpenAIForCounter()
trimmer = trim_messages(
max_tokens=65,
strategy="last",
token_counter=trim_model,
include_system=True,
allow_partial=False,
start_on="human",
)
messages_ = [
SystemMessage(content="you're a good assistant"),
HumanMessage(content="hi! I'm bob"),
AIMessage(content="hi!"),
HumanMessage(content="I like vanilla ice cream"),
AIMessage(content="nice"),
HumanMessage(content="whats 2 + 2"),
AIMessage(content="4"),
HumanMessage(content="thanks"),
AIMessage(content="no problem!"),
HumanMessage(content="having fun?"),
AIMessage(content="yes!"),
]
trimmer.invoke(messages_)
输出结果可见对历史消息进行了截留。
[SystemMessage(content="you're a good assistant", additional_kwargs={}, response_metadata={}),
HumanMessage(content='whats 2 + 2', additional_kwargs={}, response_metadata={}),
AIMessage(content='4', additional_kwargs={}, response_metadata={}),
HumanMessage(content='thanks', additional_kwargs={}, response_metadata={}),
AIMessage(content='no problem!', additional_kwargs={}, response_metadata={}),
HumanMessage(content='having fun?', additional_kwargs={}, response_metadata={}),
AIMessage(content='yes!', additional_kwargs={}, response_metadata={})]
每次调用前,把历史先“瘦身”:
workflow = StateGraph(state_schema=State)
def call_model(state: State):
trimmed_messages = trimmer.invoke(state["messages"])
prompt = prompt_template.invoke({"messages": trimmed_messages, "language": state["language"]})
response = model.invoke(prompt)
return {"messages": [response]}
workflow.add_edge(START, "model")
workflow.add_node("model", call_model)
memoroy = MemorySaver()
app = workflow.compile(checkpointer=memory)
效果:
- 只保留最近N条消息+system message,保证模型每次都能“记得刚刚发生的事”,不被旧消息拖慢。
- 保证多轮对话的“记忆力”总是最适合当前业务。
四、流式输出:让机器人像真人一样“边想边说”
测试工程师肯定有过和 LLM 聊天“等半天”的体验吧?
LangChain 支持流式输出(streaming)——让对话助手想到哪说到哪,秒变“打字机器人”,极大提升交互体验!
config = {"configurable": {"thread_id": "abc789"}}
query = "请帮我生成一个插入排序的代码"
language = "python"
input_messages = [HumanMessage(query)]
for chunk, metadata in app.stream(
{"messages": input_messages, "language": language}, config, stream_mode="messages",
):
if isinstance(chunk, AIMessage):
print(chunk.content, end="")
实际体验:
- 用户输入一长串测试场景或复杂问题,机器人会一边生成一边输出,响应“秒见首句”,极大提升体验。
五、实战场景串讲
1. 用 Prompt 定制专业风格
- 让机器人自动以“测试专家”的口吻回复
- 输出测试用例时必须带编号、分级、预期结果等
- “你是一个精通Web安全测试的专家,请用中文回答所有问题……”
2. 用裁剪保证业务连续性
- 聊复杂测试项目时,始终记住最近关键信息,不让历史“淹没新问题”
- 复盘老对话时,精确控制上下文,避免无关信息占据token
3. 用流式提升体验
- 回答测试报告生成、用例推理等慢任务时,让用户“秒见结果”,大幅降低等待焦虑
六、写给测试工程师的Tips
- Prompt模板是“机器人性格和业务规范”的入口:写Prompt就像写测试计划,越精细越有效。
- 状态管理让机器人“记住你的偏好”:比如语言、角色、输出格式、项目编号等,都可以做成state参数。
- 历史裁剪让多轮对话更持久、更高效:不用担心忘记历史,也不用担心超载。
- 流式输出让交互体验媲美真人:任何慢任务都能优雅展示进度。
结语
LangChain 让每个测试工程师都能拥有自己的“超级测试助手”——既懂你的业务,又会高效对话,还能输出专业级别的答案。只要用好 Prompt 模板和上下文管理,你的测试机器人将成为团队的“智慧左膀右臂”!
下期预告:如何结合 LangChain、RAG 技术让机器人基于测试用例库/缺陷库实现“知识检索+对话”一体化?
持续关注,测试智能化之路越走越宽!