CrewAI框架添加知识源

官方的文档如下

https://docs.crewai.com/concepts/knowledge

但是不知道为什么,可能是版本的问题(我用的是0.86.0),参考官方文档的配置我会报错,并且也导入不了数据库,也可能用的不是官方API。本文以常用的csvjsonpdf作为知识库进行举例

重点:下面的代码是基于0.83.0版本的!!!最新版本(0.108.0)框架的配置可以移步文章底部补充
在这里插入图片描述

使用csv文件作为数据源

def csv_knowledge_source():
    # 指定向量数据库持久化文件夹(如需要可取消注释)
    os.environ["CREWAI_STORAGE_DIR"] = "vector_store_csv"

    current_dir = Path(__file__).parent
    csv_path = current_dir / "files/high_school_scores.csv"

    if not csv_path.exists():
        raise FileNotFoundError(f"CSV file not found at {csv_path}")

    csv_source = CSVKnowledgeSource(
        file_path=csv_path,
        metadata={"preference": "score"}
    )

    openai_api_base = os.getenv("OPENAI_API_BASE")
    openai_api_key = os.getenv("OPENAI_API_KEY")

    if not openai_api_base or not openai_api_key:
        raise ValueError("OPENAI_API_BASE or OPENAI_API_KEY not set.")

    agent = Agent(
        role="高中老师",
        goal="你了解学生的所有成绩",
        backstory="你经常关注学生的成绩",
        verbose=True,
    )

    task = Task(
        description="使用知识库中的信息回答有关学生成绩的问题: {question}",
        expected_output="基于知识库数据的解答:",
        agent=agent,
    )

    crew = Crew(
        agents=[agent],
        tasks=[task],
        verbose=True,
        process=Process.sequential,
        knowledge={
            "sources": [csv_source],
            # "embedder": {
            #     "provider": "openai",
            #     "api_base": openai_api_base,  # 移除了config层级
            #     "api_key": openai_api_key,
            #     "model": "text-embedding-3-small"
            # }
        }
    )

    try:
        result = crew.kickoff(inputs={"question": "孙七的语文成绩是多少"})
        print(result)
    except Exception as e:
        print(f"An error occurred: {e}")

high_school_scores.csv文件

学生姓名,语文成绩,数学成绩,英语成绩
张三,63,137,66
李四,82,98,83
王五,66,50,96
赵六,57,109,145
孙七,136,121,147

在这里插入图片描述

使用json文件作为数据源

def json_knowledge_source():
    # 指定向量数据库持久化文件夹
    os.environ["CREWAI_STORAGE_DIR"] = "vector_store_json"

    # 获取当前位置路径
    current_dir = Path(__file__).parent
    # 指定到文件路径
    json_path = current_dir / "files/high_school_scores.json"

    json_source = JSONKnowledgeSource(
        file_path=json_path, metadata={"preference": "personal"}
    )

    agent = Agent(
        role="高中老师",
        goal="你了解学生的所有成绩",
        backstory="""你经常关注学生的成绩""",
        verbose=True,
    )

    task = Task(
        description="使用知识库中的信息回答有关学生成绩的问题: {question}",
        expected_output="基于知识库数据的解答:",
        agent=agent,
    )

    crew = Crew(
        agents=[agent],
        tasks=[task],
        verbose=True,
        process=Process.sequential,
        knowledge={
            "sources": [json_source],
            "metadata": {"preference": "personal"},
            # "embedder_config": {
            #     "provider": "openai",
            #     "config": {"model": "text-embedding-3-small"}
            # }
        }
    )


    crew.kickoff(inputs={"question": "孙七的语文成绩是多少"})

high_school_scores.json

[
    {
        "姓名": "张三",
        "语文": 63,
        "数学": 137,
        "英语": 66
    },
    {
        "姓名": "李四",
        "语文": 82,
        "数学": 98,
        "英语": 83
    },
    {
        "姓名": "王五",
        "语文": 66,
        "数学": 50,
        "英语": 96
    },
    {
        "姓名": "赵六",
        "语文": 57,
        "数学": 109,
        "英语": 145
    },
    {
        "姓名": "孙七",
        "语文": 136,
        "数学": 121,
        "英语": 147
    }
]

在这里插入图片描述

使用pdf文件作为数据源

def pdf_knowledge_source():
    # 指定向量数据库持久化文件夹
    os.environ["CREWAI_STORAGE_DIR"] = "vector_store_pdf"

    # 获取当前位置路径
    current_dir = Path(__file__).parent
    # 指定到文件路径
    pdf_path = current_dir / "files/人物介绍.pdf"

    pdf_source = PDFKnowledgeSource(
        file_path=pdf_path, metadata={"preference": "personal"}
    )

    agent = Agent(
        role="About User",
        goal="你了解文档的一切。",
        backstory="""你是一个回答文档内容的高手。""",
        verbose=True
    )

    task = Task(
        description="回答有关用户的问题: {question}",
        expected_output="解答问题。",
        agent=agent,
    )

    crew = Crew(
        agents=[agent],
        tasks=[task],
        verbose=True,
        process=Process.sequential,
        knowledge={
            "sources": [pdf_source],
            "metadata": {"preference": "personal"},
        }
    )

    crew.kickoff(inputs={"question": "张三的基本信息?"})

人物介绍.pdf

张三,35 岁,是一位在科技领域崭露头角的软件工程师。他毕业于国内顶尖学府的计算机科学专业,凭借扎实的专业知识和对技术的热爱,在行业内积累了丰富的经验。
张三性格沉稳且富有创造力,面对复杂的技术难题,总能冷静分析,找到创新的解决方案。工作之余,他还是个户外运动爱好者,经常参与登山、骑行活动,这不仅锻炼了他的体魄,也培养了他坚韧不拔的毅力。在团队合作中,张三善于倾听他人意见,凭借出色的沟通能力,总能高效地协调团队成员,推动项目顺利进行。无论是工作还是生活,他都以积极的态度影响着身边的人,是大家眼中的榜样。

在这里插入图片描述
参考资料:

https://www.bilibili.com/video/BV1jPBfYfE8C

2.20 补充

向量数据库的本地存储位置,Win系统的在这里

C:\Users\用户名\AppData\Local\CrewAI

快速浏览:

Win+R,然后粘贴

explorer.exe C:\Users\%USERNAME%\AppData\Local\CrewAI

如果使用的版本是0.86.0的,将会出现如下错误,暂时还不知道是什么原因。并且目前还不可以使用自定义的embedding层。借此博文,也希望抛砖引玉一下,求助怎么解决上述问题~
在这里插入图片描述

3.20 补充

更新到了最新的crewai 0.108.0版本
image-20250324104258312

使用如下的配置可以正常使用知识库和自定义embedder
划重点!!!!!!!正确的写法是knowledge_sources而不是knowledge_source,否则不会进行数据向量化,而且还不报错,智能体还调用不了这个知识库,这个卡了我一天!!!

from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task
from crewai.knowledge.source.json_knowledge_source import JSONKnowledgeSource
from dotenv import load_dotenv
import os

load_dotenv()

@CrewBase
class SimpleKnowledgeExample:
    """SimpleKnowledgeExample crew"""

    agents_config = "config/agents.yaml"
    tasks_config = "config/tasks.yaml"

    json_knowledge_source = JSONKnowledgeSource(
        file_paths=["lorenze.json", "random.json"]
    )

    @agent
    def researcher(self) -> Agent:
        return Agent(config=self.agents_config["researcher"], verbose=True)

    @task
    def research_task(self) -> Task:
        return Task(
            config=self.tasks_config["research_task"],
        )

    @crew
    def crew(self) -> Crew:
        """Creates the SimpleKnowledgeExample crew"""

        return Crew(
            agents=self.agents,
            tasks=self.tasks,
            process=Process.sequential,
            verbose=True,
            knowledge_sources=[self.json_knowledge_source],
            embedder={
                "provider": "ollama",
                "config": {
                    "model": "nomic-embed-text:latest",
                    # "api_key": GEMINI_API_KEY,
                    "api_base": "http://localhost:11434",
                }
            }
            # embedder={
            #     "provider": "openai",
            #     "config": {
            #         "model": "text-embedding-3-small",
            #         "api_key": os.getenv("OPENAI_API_KEY"),
            #         "api_base": os.getenv("OPENAI_API_BASE"),
            #     }
            # }
        )

文件目录如下:

image-20250324104445601

效果如下:
image-20250324105257929

后台日志也显示用到了自己的embedder

image-20250324105340949

但是还有bug,不能使用命令清除knowledge,需要从本地自己删除(目录见上文)

image-20250324105037230
此外,传入的路径也可以使用相对路径,knowledge也不用局限于图中的位置

    # 获取当前位置路径
    current_dir = Path(__file__).parent
    # 获取当前位置的上一级路径
    parent_dir = current_dir.parent.parent
    # 标准知识库文件
    random_path = parent_dir / "my_knowledge/random.json"
    lorenze_path = parent_dir / "my_knowledge/random.json"
    print(random_path, lorenze_path)

    json_knowledge_source = JSONKnowledgeSource(
        file_paths=[random_path, lorenze_path]
    )

可以把knowledge放在项目根目录,文件夹也不限于knowledge这个名称(比如改成my_knowledge)

image-20250324111706294

3.24 补充

数据集不支持中文

看GitHub的ISSUE #2454里应该是一个Bug,数据集的名称目前不支持中文,会生成knowledge但是不会查询到里面的信息

数据集里有中文内容不会影响

image-20250324175914218

Agent里面的Role内容也不能为中文

而goal和backstory可以为中文,不会影响程序正常运行

image-20250324181421337

附部分源码:

def set_knowledge(self, crew_embedder: Optional[Dict[str, Any]] = None):
    try:
        if self.embedder is None and crew_embedder:
            self.embedder = crew_embedder

        if self.knowledge_sources:
            full_pattern = re.compile(r"[^a-zA-Z0-9\-_\r\n]|(\.\.)")
            knowledge_agent_name = f"{re.sub(full_pattern, '_', self.role)}"
            if isinstance(self.knowledge_sources, list) and all(
                isinstance(k, BaseKnowledgeSource) for k in self.knowledge_sources
            ):
                self.knowledge = Knowledge(
                    sources=self.knowledge_sources,
                    embedder=self.embedder,
                    collection_name=knowledge_agent_name,
                    storage=self.knowledge_storage or None,
                )
    except (TypeError, ValueError) as e:
        raise ValueError(f"Invalid Knowledge Configuration: {str(e)}")
<think>好的,我现在需要解决用户在使用CrewAI生成SQL语句时,总是返回带有Markdown代码块样式的问题。用户希望得到纯净的SQL语句,不带任何格式。首先,我得回想一下CrewAI的相关知识,特别是工具的使用和输出的处理。 用户之前询问过关于CrewAI中工具的使用方法和原理,现在的问题集中在输出格式上。可能的原因有几个:CrewAI默认的响应格式可能包含了Markdown的代码块,或者代理在处理工具输出时自动添加了这些格式。此外,用户在定义工具或代理配置时可能有某些设置导致了这个情况。 首先,我需要检查CrewAI的文档,看看是否有关于输出格式控制的配置选项。通常,这类框架允许通过参数来调整输出的格式,比如设置是否启用Markdown渲染。例如,在创建代理时,可能有verbose参数或类似选项影响输出样式。 其次,用户提到的返回结果是```sql select * from user ```,这说明输出被包裹在Markdown的代码块中。解决方案可能包括修改代理的配置,或者在工具处理结果后手动去除这些格式。例如,在工具函数中返回结果之前,可以处理字符串,去掉Markdown语法。 另外,可能需要自定义工具的输出处理逻辑。CrewAI的工具使用装饰器@tool,可能允许在工具定义时指定输出的处理方式。例如,可以添加后处理步骤,将结果中的Markdown标记去除。 还有一种可能是代理的响应生成机制默认使用Markdown格式化代码。在这种情况下,调整代理的响应模板或禁用自动格式化功能可以解决问题。例如,在创建代理时设置特定的参数,如response_format="raw"之类的选项,如果有的话。 如果文档中没有直接的配置选项,可能需要通过字符串操作来处理结果。例如,在获取到代理的响应后,使用正则表达式提取SQL语句,去除包围的```sql和```。这可以在工具执行后的结果处理步骤中实现,或者在代理的输出钩子(hook)中进行处理。 此外,用户可能需要确保他们的工具函数返回的是纯文本,而不是包含Markdown格式的字符串。检查工具函数的实现,确保没有意外添加了格式。例如,工具函数可能错误地使用f-string插入了Markdown符号,需要修正为返回纯SQL字符串。 可能的解决方案步骤包括: 1. 检查代理配置,禁用Markdown格式化输出。 2. 在工具函数返回结果前去除格式。 3. 使用后处理函数清理代理的响应。 4. 自定义工具装饰器参数,指定输出格式。 需要验证这些方法的可行性。例如,假设代理的verbose参数控制输出格式,设置verbose=False可能减少装饰性内容。但用户可能需要保留其他详细输出,因此需要更精细的控制。 另外,可能需要查阅CrewAI的源代码或社区讨论,看看其他用户是否遇到类似问题,是否有已知的解决方案或最佳实践。例如,可能需要在工具定义时使用特定的参数,或者在创建任务时指定输出的格式。 总结可能的解决步骤: - 修改代理配置,关闭自动Markdown格式化。 - 在工具函数中返回纯文本,避免包含```。 - 使用后处理步骤清理响应中的Markdown。 - 利用自定义输出处理器或中间件拦截并修改响应。 现在需要将这些思路整理成结构化的回答,逐步指导用户解决问题,并提供代码示例和配置建议。确保每个步骤清晰,并解释背后的原理,帮助用户理解如何调整他们的代码以实现纯净的SQL输出。</think>以下是解决 CrewAI 生成 SQL 时返回 Markdown 样式问题的完整方案: --- ### 问题根源分析 CrewAI 默认使用 Markdown 渲染输出,导致 SQL 语句包裹在 ```sql 代码块中。需通过以下方法实现纯 SQL 输出: --- ### 解决方案(分步实施) #### 方法一:配置 Agent 输出格式 ```python from crewai import Agent sql_agent = Agent( role='SQL 专家', goal='生成纯净的 SQL 语句', verbose=False, # 关闭详细模式(会减少装饰性输出) format_response=lambda response: response.replace('```sql', '').replace('```', '').strip(), # 关键参数:自定义响应格式化函数 tools=[sql_generation_tool] ) ``` #### 方法二:工具层处理(推荐) ```python from crewai import tool import re @tool("SQL生成器") def generate_sql(query: str) -> str: """根据自然语言生成SQL语句""" # 原始生成逻辑(示例) raw_sql = "SELECT * FROM users WHERE age > 25" # 清除 Markdown 包装 clean_sql = re.sub(r'```sql|```', '', raw_sql).strip() return clean_sql ``` #### 方法三:结果后处理 ```python # 执行任务后处理结果 result = crew.kickoff() clean_sql = re.search(r'```sql(.*?)```', result, re.DOTALL).group(1).strip() # 或直接替换 clean_sql = result.replace('```sql', '').replace('```', '').strip() ``` --- ### 进阶配置方案 #### 自定义输出解析器 ```python from crewai.processors import BaseProcessor class SQLProcessor(BaseProcessor): def process(self, output): return output.split('```sql')[-1].split('```')[0].strip() sql_agent = Agent( ... output_parser=SQLProcessor() # 绑定自定义解析器 ) ``` #### 工具装饰器参数控制 ```python @tool( "SQL生成工具", response_format="raw" # 假设框架支持该参数 ) def generate_sql(...): ... ``` --- ### 原理说明 1. **渲染管道**:CrewAI 的输出处理流程为 `工具原始输出 → 格式装饰器 → 最终输出` 2. **拦截点**:可通过三个层面干预: - 工具层:返回前清理格式 - Agent 层:自定义响应格式化函数 - 处理层:添加后处理解析器 3. **正则表达式**:使用 `re.sub(r'```sql|```', '', text)` 清除代码块标记 --- ### 验证测试 ```python # 测试用例 input_text = "```sql\nSELECT * FROM users\n```" expected_output = "SELECT * FROM users" # 执行清理 assert clean_sql(input_text) == expected_output ``` 建议优先采用方法二(工具层处理)结合方法一(Agent配置),可确保全流程输出纯净 SQL。若需保留其他 Markdown 内容,推荐使用方法三的后处理提取。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Otto_1027

蟹蟹你,我会继续努力的~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值