开头

嘿,这里是惬鹤频道!
经过这几天的学习,我终于完成了Agent项目的全部内容。
芜湖!
芜湖!
芜湖芜湖!!

好了不闹了,这次要带来的是剩余的两个代码文件。这两个文件不是很重要,但是依旧需要对前面相关知识的整合,
还需要见见老朋友streamlit。

顺带说一下,这次的项目编写完毕后,在想出下一个项目要做什么之前,可能不会有太多新博客发布,感谢大家的支持!
我也许很快就会回归,希望后面还能和大家见面。请多多支持!

那让我们开始吧!

前端代码:app.py

"""
文件名:app.py
描述:利用streamlit进行网页端的编写
"""
# 依赖导入
import time
import streamlit as st

# 依赖文件导入
from agent.react_agent import ReactAgent

# 设置页面标题
st.title("智扫通机器人智能客服")
# 添加一条水平分割线,美化页面
st.divider()

# 初始化会话状态中的 Agent 实例(只会执行一次)
if "agent" not in st.session_state:
    st.session_state["agent"] = ReactAgent()

# 初始化会话状态中的消息历史列表(只会执行一次)
if "message" not in st.session_state:
    st.session_state["message"] = []

# 遍历历史消息,在页面上显示出来
for message in st.session_state["message"]:
    st.chat_message(message["role"]).write(message["content"])

# 页面底部显示聊天输入框,用户输入后按回车触发
prompt = st.chat_input()

# 如果用户输入了内容
if prompt:
    # 立即在界面上显示用户发送的消息
    st.chat_message("user").write(prompt)
    # 将用户消息追加到历史记录中
    st.session_state["message"].append({"role": "user", "content": prompt})

    # 用于收集 AI 响应的所有片段(完整内容)
    response_messages = []

    # 显示“思考中”的加载动画
    with st.spinner("智能客服思考中。。。"):
        # 调用 Agent 的流式执行方法,返回一个生成器
        res_stream = st.session_state["agent"].execute_stream(prompt)

        # 定义生成器函数,用于同时完成两件事:
        #   - 将每个响应块缓存到 cache_list 中
        #   - 将每个字符逐个 yield 出去,实现打字机效果
        def capture(generator, cache_list):
            for chunk in generator:           # 每次得到一个响应块(可能是一个字符串)
                cache_list.append(chunk)      # 缓存完整块
                for char in chunk:            # 遍历块中的每个字符
                    time.sleep(0.01)          # 控制字符输出速度(模拟打字效果)
                    yield char                # 逐个字符输出到页面

        # 在助手消息容器中实时流式输出 AI 的回答(逐字显示)
        st.chat_message("assistant").write_stream(capture(res_stream, response_messages))

        # 将完整的 AI 回答追加到历史记录中
        st.session_state["message"].append({"role": "assistant", "content": response_messages[-1]})

        # 强制页面重新运行(刷新界面),以便显示最新的历史消息
        st.rerun()

我们的老朋友:streamlit,用来生成前端页面。

一、初始化部分(页面标题、分割线)

st.title:设置页面标题

st.divider:添加水平分隔线

二、会话状态初始化

st.session_state[“agent”]:单例模式,确保整个会话只有一个 ReactAgent 实例。

st.session_state[“message”]:存储对话历史(每一条消息为 {“role”: “user”/“assistant”, “content”: “…”})。

三、显示历史消息

遍历 st.session_state[“message”],用 st.chat_message(role).write(content) 渲染每条消息。

四、用户输入处理

st.chat_input():底部输入框,用户输入后触发 if prompt 块。

4.1 显示用户消息并记录
立即在聊天区域显示用户消息。

将用户消息追加到 session_state[“message”]。

4.2 调用 Agent 流式生成
res_stream = st.session_state[“agent”].execute_stream(prompt):获得生成器(每块可能是一个字符串片段)。

定义 capture 生成器:

遍历 generator 的每个块(chunk)。

将完整块缓存到 cache_list(用于最终记录完整回答)。

再将块拆解为字符,每个字符 time.sleep(0.01) 模拟打字机效果,然后 yield char。

st.chat_message(“assistant”).write_stream(capture(…)):逐字符流式输出。

4.3 保存完整回答并刷新
将完整回答(response_messages[-1],注意这里只取了最后一个块,存在 bug)追加到历史记录。

st.rerun():强制页面重新运行,以更新消息列表(实际上 Streamlit 在回调结束后会自动 rerun,这里手动调用确保立即刷新)。

代码文件:react_agent.py

"""
文件名:react_agent.py
描述:
"""
# 导入依赖
from langchain.agents import create_agent
from model.factory import chat_model
from utils.prompt_loader import load_system_prompts
from agent.tools.agent_tools import (rag_summarize, get_weather, get_user_id, get_user_location,
                                     get_current_month, fetch_external_data, fill_context_for_report)
from agent.tools.middleware import monitor_tool, log_before_model, report_prompt_switch

# 创建智能体
class ReactAgent:
    def __init__(self):
        self.agent = create_agent(
            model = chat_model,
            system_prompt=load_system_prompts(),
            tools=[rag_summarize, get_weather, get_user_id, get_user_location,
                   get_current_month, fetch_external_data, fill_context_for_report],
            middleware=[monitor_tool, log_before_model, report_prompt_switch],
        )
    # 接受问题,返回一个调用智能体的格式
    def execute_stream(self, query: str):
        input_dict = {
            "messages":[
                {"role": "user", "content": query}
            ]
        }

        # context就是提示词切换的标记
        for chunk in self.agent.stream(input_dict, stream_mode = "values", context={"report": False}):
            latest_message = chunk["messages"][-1]
            if latest_message.content:
                yield latest_message.content.strip() + "\n"

关于代码的解析如下:

1.依赖导入

从 langchain.agents 导入 create_agent(官方推荐的 Agent 创建方法)

从 model.factory 导入预配置的聊天模型 chat_model

从 utils.prompt_loader 导入 load_system_prompts(加载系统提示词)

从 agent.tools.agent_tools 导入 7 个自定义工具(RAG、天气、用户信息、外部数据等)

从 agent.tools.middleware 导入 3 个中间件(监控、日志、提示词切换)

2.ReactAgent 类

init 方法
调用 create_agent 创建一个 Agent 实例,并存储在 self.agent 中。

传入参数:

model:聊天模型

system_prompt:系统提示词(定义 Agent 角色、规则)

tools:工具列表

middleware:中间件列表

execute_stream 方法
输入:用户问题 query

构造输入字典:{“messages”: [{“role”: “user”, “content”: query}]}

调用 self.agent.stream,指定 stream_mode=“values”(返回完整状态),并传递 context={“report”: False}(控制提示词切换)

遍历流式输出,每次取出 chunk[“messages”][-1](最新消息)

如果消息内容非空,则 yield latest_message.content.strip() + “\n”(逐块产出内容,每块后加换行)

3.关键设计点

封装复杂性:将 create_agent 的配置细节隐藏在类内部,外部只需调用 execute_stream 即可获得流式回复。

流式输出:使用生成器 yield,适配 Streamlit 的 write_stream 方法,实现实时打字效果。

上下文传递:context={“report”: False} 用于控制 Agent 的行为(如是否切换到报告生成模式),中间件可以读取该上下文并修改提示词或执行逻辑。

4.与前端(app.py)的协作

app.py 中 st.session_state[“agent”] = ReactAgent() 创建 Agent 实例。

用户输入后,调用 res_stream = st.session_state[“agent”].execute_stream(prompt) 获得生成器。

使用 st.chat_message(“assistant”).write_stream(…) 实时显示流式输出。

四个配置文件

嗯,是不是忘记了什么?

对了,那四个配置文件我还没和大家分享,下面一起发出来。

配置文件:agent.yml

external_data_path: data/external/records.csv

配置文件:chroma.yml

collection_name: agent
persist_directory: chroma_db
k: 3
data_path: data
md5_hex_store: md5.txt
allow_knowledge_file_type: ["txt", "pdf"]

chunk_size: 200
chunk_overlap: 20
separators: ["\n\n", "\n", ".", "!", "?", "。", "!", "?", " ", ""]

配置文件:prompts.yml

main_prompt_path: prompts/main_prompt.txt
rag_summarize_prompt_path: prompts/rag_summarize.txt
report_prompt_path: prompts/report_prompt.txt

配置文件:rag.yml

chat_model_name: qwen3-max
embedding_model_name: text-embedding-v4

结尾

那么,到这里,所有的代码文件都完成了分享和解析,如果你对这个项目有兴趣,可以到如下GitHub网址进行下载:
https://github.com/QHzzy035/RoboCare-Agent
那么,下次再见了!

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐