聊聊我在家撸代码时折腾AI Agent的那些事儿

山海写码人
2026-07-23 09:54
阅读 464

作者:一个在医疗软件公司写Python的远程打工人

发布时间:2025年7月14日 凌晨1:23

标签:Python AI Agent 技术探索 远程办公


现在是凌晨一点半,窗外安静得只剩下空调的嗡嗡声。我合上笔记本电脑,伸了个懒腰,决定趁脑子还清醒,把这段时间折腾技术的一些心得记录下来。

先简单介绍一下自己吧——我在一家做医疗信息化软件的公司当Python开发,主要搞HIS(医院信息系统)相关的后端服务。去年公司开始推远程办公,我就成了"居家撸码"大军的一员。说实话,远程办公爽是爽,不用挤地铁了,但有时候也挺孤独的,写技术博客算是我给自己找的一个出口吧。

最近工作之余一直在研究Rust,那所有权机制和生命周期搞得我头秃,但确实有意思。不过今天不聊Rust,聊聊我这段时间在AI Agent方向的一些探索和实践,主要用到了智谱清言CrewAI这两个东西。

事情是这样的

上个月,我们组接了个需求——给某三甲医院的药剂科做一个"智能用药审核助手"。需求文档写得挺漂亮:基于患者病历、检验指标、用药历史,自动进行药物相互作用审查,给出风险提示和建议。

产品经理开会的时候说得轻巧:"不就是调个大模型的API嘛,一周搞定。"

我当时就想翻白眼。兄弟,这是医疗场景啊,你让一个幻觉率感人的人工智能随便给用药建议?出了事谁负责?

但需求已经排进Sprint了,deadline就摆在那。我想了想,与其让大模型直接给结论,不如让它当一个"审核员",把规则引擎的结果做一层智能解读和补充。说白了,就是搞一个AI Agent的工作流。

为什么选智谱清言

技术选型这块,我纠结了好几天。OpenAI的GPT-4肯定好用,但有两个问题:一是数据合规,医疗数据出境这事儿太敏感了,公司合规部门直接一票否决;二是成本,按我们的调用量算下来,一个月光API费用就得小几万。

后来同事推荐我试试智谱清言(GLM系列模型)。说实话,一开始我是抱着"国产能行吗"的心态去试的,结果还真让我有点惊喜。

几个打动我的点:

对比维度 GPT-4 智谱清言(GLM-4)
数据合规 数据出境,合规风险高 国内部署,完全合规 ✅
API价格 约$30/1M tokens 约¥60/1M tokens,便宜一大截 ✅
中文医疗术语理解 还行,偶尔犯傻 对中文医学术语理解明显更好 ✅
响应速度 偶尔抽风 比较稳定 ✅
Function Calling 成熟 支持,基本够用 ✅

最让我满意的是它对中文医疗术语的理解。比如"丙氨酸氨基转移酶"和"ALT"它都知道是一回事,GPT-4有时候还会把"他汀类药物"跟"他唑"搞混,属实离谱。

# 智谱清言 API 调用示例
from zhipuai import ZhipuAI

client = ZhipuAI(api_key="your-api-key")

response = client.chat.completions.create(
    model="glm-4",
    messages=[
        {
            "role": "system",
            "content": "你是一名专业的临床药师,负责审核处方中的药物相互作用风险。"
        },
        {
            "role": "user",
            "content": "患者正在服用华法林,新处方增加了阿司匹林,请评估风险。"
        }
    ],
    tools=[
        {
            "type": "function",
            "function": {
                "name": "check_drug_interaction",
                "description": "查询两种药物之间的相互作用信息",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "drug_a": {"type": "string", "description": "药物A名称"},
                        "drug_b": {"type": "string", "description": "药物B名称"}
                    },
                    "required": ["drug_a", "drug_b"]
                }
            }
        }
    ]
)

CrewAI登场:多Agent协作才是正道

光有大模型还不够。我们的场景其实挺复杂的——需要查药品数据库、需要看患者历史用药、需要比对检验指标、最后还要生成一份结构化的审核报告。一个Agent根本搞不定。

这时候CrewAI就派上用场了。

CrewAI是一个Python框架,专门用来编排多个AI Agent协同工作。你可以把它理解成给一群AI"分工派活"的工具。每个Agent有自己的角色、目标和工具,它们之间可以互相传递信息、协作完成任务。

我当时看到CrewAI的文档,第一反应是:这不就是给AI搞了个"项目管理"嘛。Agent是"员工",Task是"工单",Crew是"项目组"。嘿,这比喻还挺贴切的。

我设计的Agent工作流大概是这样的:

[数据采集Agent] → [规则审核Agent] → [智能解读Agent] → [报告生成Agent]
       ↓                ↓                  ↓                  ↓
  拉取患者信息     比对药物相互作用     结合临床给出建议     输出结构化报告
  检验指标等       查询禁忌症等         评估风险等级         格式化输出

来看看核心代码长什么样:

from crewai import Agent, Task, Crew, Process
from crewai_tools import tool
import requests

# 定义工具函数
@tool("查询药物相互作用数据库")
def check_interaction(drug_a: str, drug_b: str) -> str:
    """查询两种药物之间的相互作用信息"""
    # 这里调用我们内部的药品知识库API
    resp = requests.get(
        f"http://internal-api/drug-interaction",
        params={"drug_a": drug_a, "drug_b": drug_b}
    )
    return resp.json().get("result", "未查到相关信息")

@tool("获取患者用药历史")
def get_patient_med_history(patient_id: str) -> str:
    """获取患者近3个月的用药记录"""
    resp = requests.get(f"http://internal-api/patient/{patient_id}/med-history")
    return resp.json().get("history", "无记录")

# 定义Agent
data_agent = Agent(
    role="医疗数据采集专员",
    goal="准确获取患者的基本信息、当前用药和检验指标",
    backstory="你是一个严谨的医疗数据管理员,对数据准确性有极高的要求。",
    tools=[get_patient_med_history],
    verbose=True,
    allow_delegation=False
)

review_agent = Agent(
    role="药物相互作用审核员",
    goal="基于规则引擎和药品知识库,全面审查处方中的潜在风险",
    backstory="你是一名资深临床药师,有20年的处方审核经验,对药物相互作用了如指掌。",
    tools=[check_interaction],
    verbose=True,
    allow_delegation=True
)

interpret_agent = Agent(
    role="临床建议分析师",
    goal="结合患者具体情况,给出个性化的用药调整建议",
    backstory="你是一名临床药学专家,擅长将复杂的药物相互作用信息转化为医生能理解的建议。",
    verbose=True,
    allow_delegation=True
)

report_agent = Agent(
    role="审核报告生成专员",
    goal="将审核结果整理成结构化的、符合医院规范的审核报告",
    backstory="你是一名医疗文档专家,熟悉各类医疗报告的格式和规范要求。",
    verbose=True,
    allow_delegation=False
)

# 定义任务
task1 = Task(
    description="获取患者{patient_id}的完整用药信息和近期检验指标",
    expected_output="患者的用药历史列表和关键检验指标",
    agent=data_agent
)

task2 = Task(
    description="审查当前处方与患者用药历史之间的药物相互作用风险",
    expected_output="详细的药物相互作用分析,包括风险等级和具体机制",
    agent=review_agent,
    context=[task1]
)

task3 = Task(
    description="基于审核结果,结合患者肝肾功能等指标,给出个性化建议",
    expected_output="包含风险评估和具体调整建议的分析报告",
    agent=interpret_agent,
    context=[task2]
)

task4 = Task(
    description="生成最终的处方审核报告,包含风险等级、问题列表和建议",
    expected_output="JSON格式的结构化审核报告",
    agent=report_agent,
    context=[task3]
)

# 组建团队并执行
crew = Crew(
    agents=[data_agent, review_agent, interpret_agent, report_agent],
    tasks=[task1, task2, task3, task4],
    process=Process.sequential,
    verbose=True
)

result = crew.kickoff(inputs={"patient_id": "P20250714001"})

踩过的坑,说多了都是泪

看着代码挺优雅的是吧?实际开发的时候,我踩的坑能填满一个化粪池。

坑一:Agent之间的"传话游戏"

CrewAI的Agent之间传递信息,本质上就是把上一个Agent的输出文本塞给下一个Agent当输入。问题是什么呢?信息在传递过程中会"失真"。

比如数据采集Agent拉了一大堆检验指标,传给审核Agent的时候,审核Agent可能只关注了其中几个,把其他数据"创造性地"忽略了。有一次它甚至把患者的肌酐值120看成了210,差点给出"建议停药"的离谱建议。

我的解决方案是在每个Task的description里把关键字段明确列出来,并且加了一句"你必须完整引用前序任务中的所有数据,不得遗漏或修改"。虽然有点笨,但确实管用。

坑二:Token消耗比想象中猛

四个Agent串行执行,每个Agent都有自己的system prompt和context,token消耗是指数级增长的。一开始我没注意,跑了几十次测试,智谱清言的账户余额直接见底。

后来我做了几个优化:

  • 精简每个Agent的backstory,去掉那些"花里胡哨"的人设描述
  • 对中间结果做截断,不需要的信息不往下传
  • 加了一个缓存层,相同的药物相互作用查询直接走Redis

优化之后,单次审核的token消耗从大约8000降到了3000左右,成本直接砍了60%。

坑三:输出格式不稳定

报告生成Agent有时候会"自由发挥",输出的JSON格式不统一。今天给你多个字段,明天给你少个字段,下游系统解析直接报错。

最后我在prompt里加了few-shot examples,把期望的输出格式写死,同时在代码层加了JSON Schema校验,格式不对就让它重新生成。虽然多花了几秒钟,但至少不会炸了。

import jsonschema

REPORT_SCHEMA = {
    "type": "object",
    "properties": {
        "risk_level": {"type": "string", "enum": ["低", "中", "高", "极高"]},
        "issues": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "drug_pair": {"type": "array", "items": {"type": "string"}},
                    "severity": {"type": "string"},
                    "mechanism": {"type": "string"},
                    "suggestion": {"type": "string"}
                },
                "required": ["drug_pair", "severity", "suggestion"]
            }
        },
        "overall_suggestion": {"type": "string"}
    },
    "required": ["risk_level", "issues", "overall_suggestion"]
}

def validate_report(report_json: dict) -> bool:
    try:
        jsonschema.validate(instance=report_json, schema=REPORT_SCHEMA)
        return True
    except jsonschema.ValidationError as e:
        print(f"报告格式校验失败: {e.message}")
        return False

最终效果

折腾了差不多三周(中间还加了两天班赶进度),这个智能用药审核助手总算上线了。跑了一个月的数据,效果还不错:

指标 数据
日均审核处方量 约1200份
药物相互作用检出率 94.7%(规则引擎单独跑是82.3%)
假阳性率 从23%降到9%
平均审核耗时 3.2秒/份
药剂科满意度 4.6/5.0

最让我开心的是,药剂科的主任跟我说,以前他们审一张处方要翻半天书,现在AI先把初筛做了,他们只需要复核高风险的就行了,效率提升了不止一倍。

听到这种反馈的时候,说实话,加班的那些怨气都散了。

一些心得体会

最后随便聊几点感受吧,不一定对,就当是碎碎念。

1. AI Agent不是万能的,但确实好用

别把Agent想得太神,它本质上还是大模型在驱动,该幻觉的时候照样幻觉。但如果你能把它放在合适的场景里,给它足够的约束和校验,它真的能解决很多实际问题。

2. 技术选型要务实

智谱清言不是最强的模型,但在我们的场景里,它是最合适的。合规、成本、中文能力,这三点缺一不可。不要盲目追新追强,适合业务的才是最好的。

3. CrewAI适合快速验证,生产环境还得打磨

CrewAI做原型验证是真的快,半天就能搭出一个多Agent工作流。但要上生产,你还需要自己加很多"防护网"——错误重试、超时控制、输出校验、日志追踪等等。框架不会帮你做这些脏活累活。

4. 远程办公需要自律

说回我自己,在家办公最大的挑战其实是自律。没有同事在旁边卷,很容易就摸鱼了。我给自己定了个规矩:每天至少写200行有效代码(不算注释和空行),完不成就不能开游戏。这个博客就是在这种"自律"下产出的,哈哈。


好了,凌晨两点了,该睡了。明天还得跟测试对Bug呢,听说他们又提了个"AI给出的建议跟医生经验不一致"的bug,这锅我可不背,AI又不是医生,建议仅供参考好吧。

下次有机会再聊聊Rust的学习心得吧,那玩意儿又是另一个坑了。

晚安,各位码农。🌙


如果这篇文章对你有帮助,欢迎点赞、收藏、转发。有问题可以在评论区交流,我远程摸鱼的时候可能会回你。

评论 0

最热最新
暂无评论
山海写码人Lv.1
0
影响力
0
文章
0
粉丝