入门 Eva J Patel(freeCodeCamp) 2026-09-10 16:14:02 · 0 阅读

第19章 构建文件分析 AI Agent

接下来,我们将把书中涉及的几个概念结合起来,搭建一个文件分析 AI Agent的架构。

这个项目在 Gradio 实战中特别实用,因为它融合了多个核心概念:

  • 文件上传

  • 文本提取

  • 状态管理(State)

  • AI 模型

  • 聊天界面

  • 多输入

  • 错误处理

什么让它成为 Agent?

在 AI 领域,"agent" 这个词的含义五花八门。

本项目采用一个务实的定义:AI Agent 是一个能接收信息、判断需要何种处理、调用工具或函数、并生成有效回复的系统。

我们的文件分析应用可以:

  1. 接收文档

  2. 提取内容

  3. 存储处理后的文本

  4. 接收用户提问

  5. 分析文档

  6. 生成回答

工作流程

应用按以下流程运行:

上传文档

接着:

提取文本

然后:

存储文档上下文

再然后:

用户提问

最后:

AI 分析相关内容

从文档提取开始

为了简洁,我们先从文本文件入手。

def extract_text(file):
    if file is None:
        return ""

    with open(file.name, "r", encoding="utf-8") as f:
        return f.read()

存储提取的文本

使用 State:

document_text = gr.State("")

接着:

extract_button.click(
    fn=extract_text,
    inputs=file,
    outputs=[document_text, preview]
)

添加提问框

question = gr.Textbox(
    label="Ask a question",
    placeholder="What does this document say about..."
)

编写分析函数

def answer_question(document, question):
    if not document:
        return "Please upload a document first."

    if not question.strip():
        return "Please enter a question."

    return (
        "An AI model would analyze the document "
        "and answer the question here."
    )

接入模型

真实的函数大概会变成这样:

def answer_question(document, question):
    prompt = f"""
    Answer the user's question using only the document below.

    DOCUMENT:
    {document}

    QUESTION:
    {question}
    """

    return model.generate(prompt)

为什么要限定文档范围

如果目标是文档问答,通常希望模型只依赖给定的文档作答。

否则,模型可能基于自身的一般知识来回答,导致结果产生误导。

更强的指令可以这样写:

Use only the provided document.
If the answer cannot be found, say that the document does not contain enough information.

处理大文档

每次提问都把整个大文档发给模型,效率可能很低。

设想一个 300 页的 PDF,用户每次问:

What was the conclusion?

你肯定不想每次都把 300 页全部发过去。

这时检索技术就派上用场了。

把文档切分成块

可以把文档切分成更小的片段。

概念上就是:

chunks = split_document(document)

例如:

Chunk 1
Chunk 2
Chunk 3
...
Chunk 100

找到相关的块

检索系统可以在这些块中搜索与用户问题相关的内容,然后只把最相关的片段发给模型。

这种模式通常被称为检索增强生成(retrieval-augmented generation,RAG)。

一个简化的检索流程

Document
→ Split into chunks
→ Store chunks
→ User asks question
→ Retrieve relevant chunks
→ Send chunks + question to model
→ Generate answer

为 Chunks 添加状态

可以保存处理后的 chunks:

chunks_state = gr.State([])

文档处理完成后:

def process_document(file):
    text = extract_text(file)
    chunks = split_text(text)

    return chunks, text

然后:

process_button.click(
    fn=process_document,
    inputs=file,
    outputs=[chunks_state, preview]
)

基于检索的问答

概念上:

def answer_question(chunks, question):
    relevant_chunks = retrieve(chunks, question)

    context = "\n\n".join(relevant_chunks)

    prompt = f"""
    Use the following context to answer the question.

    CONTEXT:
    {context}

    QUESTION:
    {question}
    """

    return model.generate(prompt)

添加对话历史

当用户可以追问时,文件分析 Agent 会实用得多。

例如:

User:
What is this report about?

Assistant:
It discusses...

User:
Who conducted the study?

Assistant:
The study was conducted by...

User:
When was it published?

Assistant:
According to the document...

聊天机器人需要同时利用文档上下文和对话上下文。

完整架构

一个简化版的应用大致如下:

import gradio as gr

def process_document(file):
    if file is None:
        return "", "No document uploaded."

    text = extract_text(file)

    return text, text[:5000]


def answer_question(document, question, history):
    if not document:
        return "Please upload a document first."

    if not question.strip():
        return "Please enter a question."

    prompt = f"""
    Answer the question using the document.

    DOCUMENT:
    {document}

    QUESTION:
    {question}
    """

    return call_model(prompt)


with gr.Blocks() as demo:
    gr.Markdown("# File Analysis AI Agent")

    document = gr.State("")

    with gr.Row():
        with gr.Column():
            file = gr.File(
                label="Upload Document"
            )

            process_button = gr.Button(
                "Process Document"
            )

            preview = gr.Textbox(
                label="Document Preview",
                lines=15
            )

        with gr.Column():
            chatbot = gr.Chatbot()

            question = gr.Textbox(
                label="Ask a Question"
            )

            ask_button = gr.Button(
                "Ask"
            )

    process_button.click(
        fn=process_document,
        inputs=file,
        outputs=[document, preview]
    )

demo.launch()

这还不是一个完整的 AI Agent,这是有意为之。

应用架构才是关键所在。

为什么架构重要

你可以把所有逻辑塞进一个函数里:

def do_everything(...):
    ...

但这样很快就会变得难以理解。

更好的做法是拆分:

extract_text()
split_text()
retrieve()
build_prompt()
call_model()
format_response()

每个函数只负责一件事。

工具调用

AI Agent 能做的远不止生成文本,它还能通过工具与外部系统交互,执行模型自身无法完成的操作。

工具本质上就是一个函数,AI 模型在需要执行特定任务时调用它。比如,一个 Agent 可以拥有搜索网页、读取文件、执行计算、查询数据库或调用 API 等工具。

基本流程如下:

  1. 用户向 Agent 发出请求。

  2. Agent 判断能否凭已有知识回答,还是需要调用工具。

  3. 如果需要工具,Agent 会带上合适的参数生成一次工具调用。

  4. 工具执行相应操作并返回结果。

  5. Agent 根据返回的结果继续处理用户的请求。

  6. Agent 基于获取到的信息给出最终回答。

举个例子,用户问 AI Agent“今天纽约的天气怎么样?”,Agent 会意识到自己需要最新信息。它不会瞎猜,而是调用天气工具获取当前天气状况,再据此回答用户。

在 Gradio 应用中,工具通常以 Python 函数或外部服务的形式实现,Gradio 界面则为 Agent 提供调用这些能力的方式。

关键区别在于:模型负责判断什么时候该用工具,而工具负责实际执行操作。这样一来,AI Agent 就不再局限于生成文本,而是能真正与数据、软件、API 和其他系统交互。

该用确定性工具时就用确定性工具

既然 Python 一行代码就能算出来:

sum(values) / len(values)

就没有必要让语言模型去猜结果。

让模型做它擅长的事,需要精确计算的任务交给确定性工具。

文件分析的安全性

这个应用可能会处理任意的文档,所以要考虑:

  • 文件大小

  • 支持的格式

  • 恶意文件

  • 敏感信息

  • 临时存储

  • API 传输

  • 数据留存

如果文档会被发送到外部 AI API,用户应当知道自己的内容正在被传输给该服务。

动手试一试

构建一个文本文件分析助手,要求:

  • 接受 .txt 文件

  • 提取文本内容

  • 显示预览

  • 把文本存入 state

  • 支持提问

  • 返回答案

  • 接着升级为支持 PDF。

    再添加检索功能,避免将大文档整体发送给模型。

    核心要点

    • 文件分析 Agent 融合了多个 Gradio 概念。

    • State 可存储已提取的文档信息。

    • AI 模型可借助文档上下文回答问题。

    • 大文档受益于分块与检索。

    • 聊天历史提供对话上下文。

    • 精确计算等任务应使用确定性工具。

    • 拆分独立函数让 Agent 架构更易维护。

    • 文件处理应用需格外关注安全与隐私。

    评论 (0)