Repository: huggingface/agents-course Branch: main Commit: b2faf700bd44 Files: 439 Total size: 2.2 MB Directory structure: gitextract_ohhcdybu/ ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── i-have-a-bug-with-a-hands-on.md │ │ ├── i-have-a-question.md │ │ └── i-want-to-improve-the-course-or-write-a-new-section.md │ └── workflows/ │ ├── build_documentation.yml │ ├── build_pr_documentation.yml │ └── upload_pr_documentation.yml ├── .gitignore ├── LICENSE ├── README.md ├── quiz/ │ ├── .python-version │ ├── README.md │ ├── data/ │ │ └── unit_1.json │ ├── push_questions.py │ └── pyproject.toml ├── scripts/ │ ├── translation.py │ └── vi.py ├── translation_agreements/ │ └── ru/ │ └── TRANSLATION_AGREEMENTS.md └── units/ ├── en/ │ ├── _toctree.yml │ ├── bonus-unit1/ │ │ ├── conclusion.mdx │ │ ├── fine-tuning.mdx │ │ ├── introduction.mdx │ │ └── what-is-function-calling.mdx │ ├── bonus-unit2/ │ │ ├── introduction.mdx │ │ ├── monitoring-and-evaluating-agents-notebook.mdx │ │ ├── quiz.mdx │ │ └── what-is-agent-observability-and-evaluation.mdx │ ├── bonus-unit3/ │ │ ├── building_your_pokemon_agent.mdx │ │ ├── conclusion.mdx │ │ ├── from-llm-to-agents.mdx │ │ ├── introduction.mdx │ │ ├── launching_agent_battle.mdx │ │ └── state-of-art.mdx │ ├── communication/ │ │ └── live1.mdx │ ├── unit0/ │ │ ├── discord101.mdx │ │ ├── introduction.mdx │ │ └── onboarding.mdx │ ├── unit1/ │ │ ├── README.md │ │ ├── actions.mdx │ │ ├── agent-steps-and-structure.mdx │ │ ├── conclusion.mdx │ │ ├── dummy-agent-library.mdx │ │ ├── final-quiz.mdx │ │ ├── introduction.mdx │ │ ├── messages-and-special-tokens.mdx │ │ ├── observations.mdx │ │ ├── quiz1.mdx │ │ ├── quiz2.mdx │ │ ├── thoughts.mdx │ │ ├── tools.mdx │ │ ├── tutorial.mdx │ │ ├── what-are-agents.mdx │ │ └── what-are-llms.mdx │ ├── unit2/ │ │ ├── introduction.mdx │ │ ├── langgraph/ │ │ │ ├── building_blocks.mdx │ │ │ ├── conclusion.mdx │ │ │ ├── document_analysis_agent.mdx │ │ │ ├── first_graph.mdx │ │ │ ├── introduction.mdx │ │ │ ├── quiz1.mdx │ │ │ └── when_to_use_langgraph.mdx │ │ ├── llama-index/ │ │ │ ├── README.md │ │ │ ├── agents.mdx │ │ │ ├── components.mdx │ │ │ ├── conclusion.mdx │ │ │ ├── introduction.mdx │ │ │ ├── llama-hub.mdx │ │ │ ├── quiz1.mdx │ │ │ ├── quiz2.mdx │ │ │ ├── tools.mdx │ │ │ └── workflows.mdx │ │ └── smolagents/ │ │ ├── code_agents.mdx │ │ ├── conclusion.mdx │ │ ├── final_quiz.mdx │ │ ├── introduction.mdx │ │ ├── multi_agent_systems.mdx │ │ ├── quiz1.mdx │ │ ├── quiz2.mdx │ │ ├── retrieval_agents.mdx │ │ ├── tool_calling_agents.mdx │ │ ├── tools.mdx │ │ ├── vision_agents.mdx │ │ └── why_use_smolagents.mdx │ ├── unit3/ │ │ ├── README.md │ │ └── agentic-rag/ │ │ ├── agent.mdx │ │ ├── agentic-rag.mdx │ │ ├── conclusion.mdx │ │ ├── introduction.mdx │ │ ├── invitees.mdx │ │ └── tools.mdx │ └── unit4/ │ ├── additional-readings.mdx │ ├── conclusion.mdx │ ├── get-your-certificate.mdx │ ├── hands-on.mdx │ ├── introduction.mdx │ └── what-is-gaia.mdx ├── es/ │ ├── _toctree.yml │ ├── bonus-unit1/ │ │ ├── conclusion.mdx │ │ ├── fine-tuning.mdx │ │ ├── introduction.mdx │ │ └── what-is-function-calling.mdx │ ├── bonus-unit2/ │ │ ├── introduction.mdx │ │ ├── monitoring-and-evaluating-agents-notebook.mdx │ │ ├── quiz.mdx │ │ └── what-is-agent-observability-and-evaluation.mdx │ ├── bonus-unit3/ │ │ ├── building_your_pokemon_agent.mdx │ │ ├── conclusion.mdx │ │ ├── from-llm-to-agents.mdx │ │ ├── introduction.mdx │ │ ├── launching_agent_battle.mdx │ │ └── state-of-art.mdx │ ├── communication/ │ │ └── live1.mdx │ ├── unit0/ │ │ ├── discord101.mdx │ │ ├── introduction.mdx │ │ └── onboarding.mdx │ ├── unit1/ │ │ ├── README.md │ │ ├── actions.mdx │ │ ├── agent-steps-and-structure.mdx │ │ ├── conclusion.mdx │ │ ├── dummy-agent-library.mdx │ │ ├── final-quiz.mdx │ │ ├── introduction.mdx │ │ ├── messages-and-special-tokens.mdx │ │ ├── observations.mdx │ │ ├── quiz1.mdx │ │ ├── quiz2.mdx │ │ ├── thoughts.mdx │ │ ├── tools.mdx │ │ ├── tutorial.mdx │ │ ├── what-are-agents.mdx │ │ └── what-are-llms.mdx │ ├── unit2/ │ │ ├── introduction.mdx │ │ ├── langgraph/ │ │ │ ├── building_blocks.mdx │ │ │ ├── conclusion.mdx │ │ │ ├── document_analysis_agent.mdx │ │ │ ├── first_graph.mdx │ │ │ ├── introduction.mdx │ │ │ ├── quiz1.mdx │ │ │ └── when_to_use_langgraph.mdx │ │ ├── llama-index/ │ │ │ ├── README.md │ │ │ ├── agents.mdx │ │ │ ├── components.mdx │ │ │ ├── conclusion.mdx │ │ │ ├── introduction.mdx │ │ │ ├── llama-hub.mdx │ │ │ ├── quiz1.mdx │ │ │ ├── quiz2.mdx │ │ │ ├── tools.mdx │ │ │ └── workflows.mdx │ │ └── smolagents/ │ │ ├── code_agents.mdx │ │ ├── conclusion.mdx │ │ ├── final_quiz.mdx │ │ ├── introduction.mdx │ │ ├── multi_agent_systems.mdx │ │ ├── quiz1.mdx │ │ ├── quiz2.mdx │ │ ├── retrieval_agents.mdx │ │ ├── tool_calling_agents.mdx │ │ ├── tools.mdx │ │ ├── vision_agents.mdx │ │ └── why_use_smolagents.mdx │ ├── unit3/ │ │ ├── README.md │ │ └── agentic-rag/ │ │ ├── agent.mdx │ │ ├── agentic-rag.mdx │ │ ├── conclusion.mdx │ │ ├── introduction.mdx │ │ ├── invitees.mdx │ │ └── tools.mdx │ └── unit4/ │ ├── README.md │ ├── additional-readings.mdx │ ├── conclusion.mdx │ ├── get-your-certificate.mdx │ ├── hands-on.mdx │ ├── introduction.mdx │ └── what-is-gaia.mdx ├── fr/ │ ├── _toctree.yml │ ├── bonus-unit1/ │ │ ├── conclusion.mdx │ │ ├── fine-tuning.mdx │ │ ├── introduction.mdx │ │ └── what-is-function-calling.mdx │ ├── bonus-unit2/ │ │ ├── introduction.mdx │ │ ├── monitoring-and-evaluating-agents-notebook.mdx │ │ ├── quiz.mdx │ │ └── what-is-agent-observability-and-evaluation.mdx │ ├── bonus-unit3/ │ │ ├── building_your_pokemon_agent.mdx │ │ ├── conclusion.mdx │ │ ├── from-llm-to-agents.mdx │ │ ├── introduction.mdx │ │ ├── launching_agent_battle.mdx │ │ └── state-of-art.mdx │ ├── communication/ │ │ └── live1.mdx │ ├── unit0/ │ │ ├── discord101.mdx │ │ ├── introduction.mdx │ │ └── onboarding.mdx │ ├── unit1/ │ │ ├── README.md │ │ ├── actions.mdx │ │ ├── agent-steps-and-structure.mdx │ │ ├── conclusion.mdx │ │ ├── dummy-agent-library.mdx │ │ ├── final-quiz.mdx │ │ ├── introduction.mdx │ │ ├── messages-and-special-tokens.mdx │ │ ├── observations.mdx │ │ ├── quiz1.mdx │ │ ├── quiz2.mdx │ │ ├── thoughts.mdx │ │ ├── tools.mdx │ │ ├── tutorial.mdx │ │ ├── what-are-agents.mdx │ │ └── what-are-llms.mdx │ ├── unit2/ │ │ ├── introduction.mdx │ │ ├── langgraph/ │ │ │ ├── building_blocks.mdx │ │ │ ├── conclusion.mdx │ │ │ ├── document_analysis_agent.mdx │ │ │ ├── first_graph.mdx │ │ │ ├── introduction.mdx │ │ │ ├── quiz1.mdx │ │ │ └── when_to_use_langgraph.mdx │ │ ├── llama-index/ │ │ │ ├── README.md │ │ │ ├── agents.mdx │ │ │ ├── components.mdx │ │ │ ├── conclusion.mdx │ │ │ ├── introduction.mdx │ │ │ ├── llama-hub.mdx │ │ │ ├── quiz1.mdx │ │ │ ├── quiz2.mdx │ │ │ ├── tools.mdx │ │ │ └── workflows.mdx │ │ └── smolagents/ │ │ ├── code_agents.mdx │ │ ├── conclusion.mdx │ │ ├── final_quiz.mdx │ │ ├── introduction.mdx │ │ ├── multi_agent_systems.mdx │ │ ├── quiz1.mdx │ │ ├── quiz2.mdx │ │ ├── retrieval_agents.mdx │ │ ├── tool_calling_agents.mdx │ │ ├── tools.mdx │ │ ├── vision_agents.mdx │ │ └── why_use_smolagents.mdx │ ├── unit3/ │ │ ├── README.md │ │ └── agentic-rag/ │ │ ├── agent.mdx │ │ ├── agentic-rag.mdx │ │ ├── conclusion.mdx │ │ ├── introduction.mdx │ │ ├── invitees.mdx │ │ └── tools.mdx │ └── unit4/ │ ├── additional-readings.mdx │ ├── conclusion.mdx │ ├── get-your-certificate.mdx │ ├── hands-on.mdx │ ├── introduction.mdx │ └── what-is-gaia.mdx ├── ko/ │ ├── _toctree.yml │ ├── bonus-unit1/ │ │ ├── introduction.mdx │ │ └── what-is-function-calling.mdx │ ├── unit0/ │ │ ├── discord101.mdx │ │ ├── introduction.mdx │ │ └── onboarding.mdx │ ├── unit1/ │ │ ├── README.md │ │ ├── actions.mdx │ │ ├── agent-steps-and-structure.mdx │ │ ├── conclusion.mdx │ │ ├── dummy-agent-library.mdx │ │ ├── final-quiz.mdx │ │ ├── introduction.mdx │ │ ├── messages-and-special-tokens.mdx │ │ ├── observations.mdx │ │ ├── quiz1.mdx │ │ ├── quiz2.mdx │ │ ├── thoughts.mdx │ │ ├── tools.mdx │ │ ├── tutorial.mdx │ │ ├── what-are-agents.mdx │ │ └── what-are-llms.mdx │ ├── unit2/ │ │ ├── introduction.mdx │ │ ├── langgraph/ │ │ │ ├── building_blocks.mdx │ │ │ ├── conclusion.mdx │ │ │ ├── document_analysis_agent.mdx │ │ │ ├── first_graph.mdx │ │ │ ├── introduction.mdx │ │ │ ├── quiz1.mdx │ │ │ └── when_to_use_langgraph.mdx │ │ ├── llama-index/ │ │ │ ├── README.md │ │ │ ├── agents.mdx │ │ │ ├── components.mdx │ │ │ ├── conclusion.mdx │ │ │ ├── introduction.mdx │ │ │ ├── llama-hub.mdx │ │ │ ├── quiz1.mdx │ │ │ ├── quiz2.mdx │ │ │ ├── tools.mdx │ │ │ └── workflows.mdx │ │ └── smolagents/ │ │ ├── code_agents.mdx │ │ ├── conclusion.mdx │ │ ├── final_quiz.mdx │ │ ├── introduction.mdx │ │ ├── multi_agent_systems.mdx │ │ ├── quiz1.mdx │ │ ├── quiz2.mdx │ │ ├── retrieval_agents.mdx │ │ ├── tool_calling_agents.mdx │ │ ├── tools.mdx │ │ ├── vision_agents.mdx │ │ └── why_use_smolagents.mdx │ └── unit4/ │ └── introduction.mdx ├── ru-RU/ │ ├── _toctree.yml │ ├── bonus-unit1/ │ │ ├── conclusion.mdx │ │ ├── fine-tuning.mdx │ │ ├── introduction.mdx │ │ └── what-is-function-calling.mdx │ ├── communication/ │ │ ├── live1.mdx │ │ └── next-units.mdx │ ├── unit0/ │ │ ├── discord101.mdx │ │ ├── introduction.mdx │ │ └── onboarding.mdx │ └── unit1/ │ ├── README.md │ ├── actions.mdx │ ├── agent-steps-and-structure.mdx │ ├── conclusion.mdx │ ├── dummy-agent-library.mdx │ ├── final-quiz.mdx │ ├── get-your-certificate.mdx │ ├── introduction.mdx │ ├── messages-and-special-tokens.mdx │ ├── observations.mdx │ ├── quiz1.mdx │ ├── quiz2.mdx │ ├── thoughts.mdx │ ├── tools.mdx │ ├── tutorial.mdx │ ├── what-are-agents.mdx │ └── what-are-llms.mdx ├── vi/ │ ├── _toctree.yml │ ├── bonus-unit1/ │ │ ├── conclusion.mdx │ │ ├── fine-tuning.mdx │ │ ├── introduction.mdx │ │ └── what-is-function-calling.mdx │ ├── communication/ │ │ ├── live1.mdx │ │ └── next-units.mdx │ ├── unit0/ │ │ ├── discord101.mdx │ │ ├── introduction.mdx │ │ └── onboarding.mdx │ ├── unit1/ │ │ ├── actions.mdx │ │ ├── agent-steps-and-structure.mdx │ │ ├── conclusion.mdx │ │ ├── dummy-agent-library.mdx │ │ ├── final-quiz.mdx │ │ ├── introduction.mdx │ │ ├── messages-and-special-tokens.mdx │ │ ├── observations.mdx │ │ ├── quiz1.mdx │ │ ├── quiz2.mdx │ │ ├── thoughts.mdx │ │ ├── tools.mdx │ │ ├── tutorial.mdx │ │ ├── what-are-agents.mdx │ │ └── what-are-llms.mdx │ ├── unit2/ │ │ └── README.md │ ├── unit3/ │ │ └── README.md │ └── unit4/ │ └── README.md └── zh-CN/ ├── _toctree.yml ├── bonus-unit1/ │ ├── conclusion.mdx │ ├── fine-tuning.mdx │ ├── introduction.mdx │ └── what-is-function-calling.mdx ├── bonus-unit3/ │ ├── building_your_pokemon_agent.mdx │ ├── conclusion.mdx │ ├── from-llm-to-agents.mdx │ ├── introduction.mdx │ ├── launching_agent_battle.mdx │ └── state-of-art.mdx ├── bonus_unit2/ │ ├── introduction.mdx │ ├── monitoring-and-evaluating-agents-notebook.mdx │ ├── quiz.mdx │ └── what-is-agent-observability-and-evaluation.mdx ├── communication/ │ ├── live1.mdx │ └── next-units.mdx ├── unit0/ │ ├── discord101.mdx │ ├── introduction.mdx │ └── onboarding.mdx ├── unit1/ │ ├── README.md │ ├── actions.mdx │ ├── agent-steps-and-structure.mdx │ ├── conclusion.mdx │ ├── dummy-agent-library.mdx │ ├── final-quiz.mdx │ ├── introduction.mdx │ ├── messages-and-special-tokens.mdx │ ├── observations.mdx │ ├── quiz1.mdx │ ├── quiz2.mdx │ ├── thoughts.mdx │ ├── tools.mdx │ ├── tutorial.mdx │ ├── what-are-agents.mdx │ └── what-are-llms.mdx ├── unit2/ │ ├── introduction.mdx │ ├── langgraph/ │ │ ├── building_blocks.mdx │ │ ├── conclusion.mdx │ │ ├── document_analysis_agent.mdx │ │ ├── first_graph.mdx │ │ ├── introduction.mdx │ │ ├── quiz1.mdx │ │ └── when_to_use_langgraph.mdx │ ├── llama-index/ │ │ ├── README.md │ │ ├── agents.mdx │ │ ├── components.mdx │ │ ├── conclusion.mdx │ │ ├── introduction.mdx │ │ ├── llama-hub.mdx │ │ ├── quiz1.mdx │ │ ├── quiz2.mdx │ │ ├── tools.mdx │ │ └── workflows.mdx │ └── smolagents/ │ ├── code_agents.mdx │ ├── conclusion.mdx │ ├── final_quiz.mdx │ ├── introduction.mdx │ ├── multi_agent_systems.mdx │ ├── quiz1.mdx │ ├── quiz2.mdx │ ├── retrieval_agents.mdx │ ├── tool_calling_agents.mdx │ ├── tools.mdx │ ├── vision_agents.mdx │ └── why_use_smolagents.mdx ├── unit3/ │ ├── README.md │ └── agentic-rag/ │ ├── agent.mdx │ ├── agentic-rag.mdx │ ├── conclusion.mdx │ ├── introduction.mdx │ ├── invitees.mdx │ └── tools.mdx └── unit4/ ├── additional-readings.mdx ├── conclusion.mdx ├── get-your-certificate.mdx ├── hands-on.mdx ├── introduction.mdx └── what-is-gaia.mdx ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/ISSUE_TEMPLATE/i-have-a-bug-with-a-hands-on.md ================================================ --- name: I have a bug with a hands-on about: You have encountered a bug during one of the hands-on title: "[HANDS-ON BUG]" labels: hands-on-bug assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Please provide any informations and a **link** to your hands-on so that we can investigate. **Screenshots** If applicable, add screenshots to help explain your problem. **Additional context** Add any other context about the problem here. ================================================ FILE: .github/ISSUE_TEMPLATE/i-have-a-question.md ================================================ --- name: I have a question about: You have a question about a section of the course title: "[QUESTION]" labels: question assignees: '' --- First, the **best way to get a response fast is to ask the community** in our Discord server: https://www.hf.co/join/discord However, if you prefer you can ask here, please **be specific**. ================================================ FILE: .github/ISSUE_TEMPLATE/i-want-to-improve-the-course-or-write-a-new-section.md ================================================ --- name: I want to improve the course or write a new section about: You found a typo, an error or you want to improve a part of the course or write a full section/unit title: "[UPDATE]" labels: documentation assignees: '' --- 1. If you want to add a full section or a new unit, **please describe precisely what you want to add before starting to write it** so that we can review the idea, validate it or not, and guide you through the writing process. 2. If there's a typo, you can directly open a PR. ================================================ FILE: .github/workflows/build_documentation.yml ================================================ name: Build documentation on: push: branches: - main jobs: build: uses: huggingface/doc-builder/.github/workflows/build_main_documentation.yml@main with: commit_sha: ${{ github.sha }} package: agents-course package_name: agents-course path_to_docs: agents-course/units/ additional_args: --not_python_module languages: en zh-CN ru-RU vi es ko fr secrets: hf_token: ${{ secrets.HF_DOC_BUILD_PUSH }} ================================================ FILE: .github/workflows/build_pr_documentation.yml ================================================ name: Build PR Documentation on: pull_request: concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true jobs: build: uses: huggingface/doc-builder/.github/workflows/build_pr_documentation.yml@main with: commit_sha: ${{ github.event.pull_request.head.sha }} pr_number: ${{ github.event.number }} package: agents-course package_name: agents-course path_to_docs: agents-course/units/ additional_args: --not_python_module languages: en zh-CN ru-RU vi es ko fr ================================================ FILE: .github/workflows/upload_pr_documentation.yml ================================================ name: Upload PR Documentation on: workflow_run: workflows: ["Build PR Documentation"] types: - completed permissions: actions: write contents: write deployments: write pull-requests: write jobs: build: uses: huggingface/doc-builder/.github/workflows/upload_pr_documentation.yml@main with: package_name: agents-course hub_base_path: https://moon-ci-docs.huggingface.co/learn secrets: hf_token: ${{ secrets.HF_DOC_BUILD_PUSH }} comment_bot_token: ${{ secrets.COMMENT_BOT_TOKEN }} ================================================ FILE: .gitignore ================================================ # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover *.py,cover .hypothesis/ .pytest_cache/ cover/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 db.sqlite3-journal # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder .pybuilder/ target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv # For a library or package, you might want to ignore these files since the code is # intended to run in multiple environments; otherwise, check them in: # .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock # UV # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. # This is especially recommended for binary packages to ensure reproducibility, and is more # commonly ignored for libraries. #uv.lock # poetry # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. # This is especially recommended for binary packages to ensure reproducibility, and is more # commonly ignored for libraries. # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control #poetry.lock # pdm # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. #pdm.lock # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it # in version control. # https://pdm.fming.dev/latest/usage/project/#working-with-version-control .pdm.toml .pdm-python .pdm-build/ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm __pypackages__/ # Celery stuff celerybeat-schedule celerybeat.pid # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ # pytype static type analyzer .pytype/ # Cython debug symbols cython_debug/ # PyCharm # JetBrains specific template is maintained in a separate JetBrains.gitignore that can # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ # Ruff stuff: .ruff_cache/ # PyPI configuration file .pypirc # custom additions notebooks/unit2/llama-index/data notebooks/unit2/llama-index/alfred_chroma_db .DS_Store ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: README.md ================================================ # The Hugging Face Agents Course If you like the course, **don't hesitate to ⭐ star this repository**. This helps us to **make the course more visible 🤗**. Star the repo ## Content The course is divided into 4 units. These will take you from **the basics of agents to a final assignment with a benchmark**. Sign up here (it's free) 👉 https://bit.ly/hf-learn-agents You can access the course here 👉 https://hf.co/learn/agents-course | Unit | Topic | Description | |---------|----------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------| | 0 | [Welcome to the Course](https://huggingface.co/learn/agents-course/en/unit0/introduction) | Welcome, guidelines, necessary tools, and course overview. | | 1 | [Introduction to Agents](https://huggingface.co/learn/agents-course/en/unit1/introduction) | Definition of agents, LLMs, model family tree, and special tokens. | | 1 Bonus | [Fine-tuning an LLM for Function-calling](https://huggingface.co/learn/agents-course/bonus-unit1/introduction) | Learn how to fine-tune an LLM for Function-Calling | | 2 | [Frameworks for AI Agents](https://huggingface.co/learn/agents-course/unit2/introduction) | Overview of `smolagents`, `LangGraph` and `LlamaIndex`. | | 2.1 | [The Smolagents Framework](https://huggingface.co/learn/agents-course/unit2/smolagents/introduction) | Learn how to build effective agents using the `smolagents` library, a lightweight framework for creating capable AI agents. | | 2.2 | [The LlamaIndex Framework](https://huggingface.co/learn/agents-course/unit2/llama-index/introduction) | Learn how to build LLM-powered agents over your data using indexes and workflows using the `LlamaIndex` toolkit. | | 2.3 | [The LangGraph Framework](https://huggingface.co/learn/agents-course/unit2/langgraph/introduction) | Learn how to build production-ready applications using the `LangGraph` framework giving you control tools over the flow of your agent. | | 2 Bonus | [Observability and Evaluation](https://huggingface.co/learn/agents-course/bonus-unit2/introduction) | Learn how to trace and evaluate your agents. | | 3 | [Use Case for Agentic RAG](https://huggingface.co/learn/agents-course/unit3/agentic-rag/introduction) | Learn how to use Agentic RAG to help agents respond to different use cases using various frameworks. | | 4 | [Final Project - Create, Test and Certify Your Agent](https://huggingface.co/learn/agents-course/unit4/introduction) | Automated evaluation of agents and leaderboard with student results. | | 3 Bonus | [Agents in Games with Pokemon](https://huggingface.co/learn/agents-course/bonus-unit3/introduction) | Explore the exciting intersection of AI Agents and games. | ## Prerequisites - Basic knowledge of Python - Basic knowledge of LLMs ## Contribution Guidelines If you want to contribute to this course, you're welcome to do so. Feel free to open an issue or join the discussion in the [Discord](https://discord.gg/UrrTSsSyjb). For specific contributions, here are some guidelines: ### Small typo and grammar fixes If you find a small typo or grammar mistake, please fix it yourself and submit a pull request. This is very helpful for students. ### New unit If you want to add a new unit, **please create an issue in the repository, describe the unit, and why it should be added**. We will discuss it and if it's a good addition, we can collaborate on it. ## Citing the project To cite this repository in publications: ```bibtex @misc{agents-course, author = {Burtenshaw, Ben and Thomas, Joffrey and Simonini, Thomas and Paniego, Sergio}, title = {The Hugging Face Agents Course}, year = {2025}, howpublished = {\url{https://github.com/huggingface/agents-course}}, note = {GitHub repository}, } ``` ================================================ FILE: quiz/.python-version ================================================ 3.11 ================================================ FILE: quiz/README.md ================================================ # Agent Course quiz scripts ================================================ FILE: quiz/data/unit_1.json ================================================ [ { "question": "Which of the following best describes a Large Language Model (LLM)?", "answer_a": "A model specializing in language recognition", "answer_b": "A massive neural network that understands and generates human language", "answer_c": "A model exclusively used for language data tasks like summarization or classification", "answer_d": "A rule-based chatbot used for conversations", "correct_answer": "B" } ] ================================================ FILE: quiz/push_questions.py ================================================ import json from pathlib import Path from datasets import Dataset from huggingface_hub import HfApi ORG_NAME = "agents-course" def main(): """Push quiz questions to the Hugging Face Hub""" for file in Path("data").glob("*.json"): print(f"Processing {file}") with open(file, "r") as f: quiz_data = json.load(f) repo_id = f"{ORG_NAME}/{file.stem}_quiz" dataset = Dataset.from_list(quiz_data) print(f"Pushing {repo_id} to the Hugging Face Hub") dataset.push_to_hub( repo_id, private=True, commit_message=f"Update quiz questions for {file.stem}", ) if __name__ == "__main__": main() ================================================ FILE: quiz/pyproject.toml ================================================ [project] name = "agents-course" version = "0.1.0" description = "Add your description here" readme = "README.md" requires-python = ">=3.11" dependencies = [ "datasets>=3.2.0", "huggingface-hub>=0.27.1", "ipykernel>=6.29.5", "requests>=2.32.3", ] ================================================ FILE: scripts/translation.py ================================================ import os import sys import re from huggingface_hub import InferenceClient # Get the directory containing the current script script_dir = os.path.dirname(os.path.abspath(__file__)) default_inp_dir = os.path.join(script_dir, '..', 'units/en') default_model = "deepseek-ai/DeepSeek-R1" default_client = InferenceClient( provider="together", # api_key is read from the environment ) def auto_translate( output_lang: str, prompt: callable, inp_dir: str = default_inp_dir, model: str = default_model, client: InferenceClient = default_client ): get_output_path = lambda x: x.replace('/en', f'/{output_lang}') escape_special_tokens = lambda x: x.replace('', '<%%think%%>').replace('', '<%%/think%%>') unescape_special_tokens = lambda x: x.replace('<%%think%%>', '').replace('<%%/think%%>', '') # Get the list of all files in the directory, recursively inp_files: list[str] = [] print('Collecting files...') for root, dirs, files in os.walk(inp_dir): for file in files: if file.endswith('.mdx') or file == "_toctree.yml": fname = os.path.join(root, file) print(' +', fname) inp_files.append(fname) def write_out_file(fpath: str, content: str): base_path = os.path.dirname(fpath) os.makedirs(base_path, exist_ok=True) with open(fpath, 'w', encoding='utf-8') as f: f.write(content) # Read the content of the file and process for i, inp_file in enumerate(inp_files): out_file = get_output_path(inp_file) if os.path.exists(out_file): print(f'[{i+1}/{len(inp_files)}] Skipping file: {inp_file}') continue with open(inp_file, 'r', encoding='utf-8') as f: content: str = f.read() content = escape_special_tokens(content) if content.strip() == "": print(f'[{i+1}/{len(inp_files)}] Skipping empty file: {inp_file}') write_out_file(out_file, "") continue print(f'[{i+1}/{len(inp_files)}] Processing file: {inp_file}') stream = client.chat.completions.create( model=model, temperature=0.0, messages=[ {"role": "user", "content": prompt(content)}, ], stream=True, ) final_text = "" for chunk in stream: print(chunk.choices[0].delta.content, end="") sys.stdout.flush() final_text += chunk.choices[0].delta.content # Optionally filter ... reasoning process final_text = final_text.split('').pop().strip() # Write the output to the file final_text = unescape_special_tokens(final_text) write_out_file(out_file, final_text) print() print(f' -> Translated to: {out_file}') print("--" * 20) #break ================================================ FILE: scripts/vi.py ================================================ from translation import auto_translate output_lang = "vi" prompt = lambda content: f''' You are a translator for the Vietnamese translation team. You are tasked with translating the following text into Vietnamese. You must follow these instructions: - Translate the text into Vietnamese, while keeping the original formatting (either Markdown, MDX or HTML) - Inside code blocks, translate the comments but leave the code as-is ; If the code block contains quite plain texts, you MUST provide the translation in
tag - Do not translate inline code, the URLs and file paths - If the term is abbreviated, keep the original term and provide the translation in parentheses for the first time it appears in the text - If there are any slag or funny joke in english, keep it (do not translate) and give an explanation so vietnamese reader can understand - Use "ta", "chúng ta", "chúng mình", "các bạn" as pronouns KEEP THESE TERMS (DO NOT TRANSLATE, do NOT add translation in parentheses): model, API, SDK, CLI, HTML, GGUF, AI, training, inference, server, client, notebook, python, Hugging Face, transformers, diffusion, diffuser, data, function, LangGraph, LangChain, Llama, Gemma, token, Unit, pretrain, Live (live stream), form, format, certificate, Space, CodeAgent Also KEEP these terms but PROVIDE TRANSLATION in parentheses for the first time it appears in the text: alignment (cân chỉnh), LLM, RAG (tìm kiếm và tạo ra câu trả lời), Agent (tác nhân), Tools (công cụ), "Special Token" (token đặc biệt), "chain-of-thought" (luồng suy luận), fine-tuning (tinh chỉnh), Thought-Action-Observation (Tư duy-Hành động-Quan sát) For these terms, use the pre-defined translation: - Quick Quiz: Kiểm tra nhanh - Unit: Chương - Bonus Unit: Chương bổ trợ - Module: Mô-đun - Lesson ...: Bài ... - Course: Khóa học - state-of-the-art: hiện đại nhất - Q&A: Hỏi và Đáp - Dummy: ảo (or "giả", or "thử" depending on the context) - onboarding: làm quen - Hands-on: Thực hành - Challenge: Bài tập lớn Here is an example: - Original text: To run the models, we will use [ollama](https://ollama.com), a command line tool that allows you to run LLMs and embedding models from Hugging Face. With ollama, you **don't need** to have access to a server or cloud service to run the models. You can run the models directly **on your computer**. - Translation: Để chạy các model, ta sẽ sử dụng [ollama](https://ollama.com), một công cụ dòng lệnh cho phép bạn chạy LLMs và embedding models từ Hugging Face. Với ollama, bạn **không cần** phải tạo server hay truy cập API bên thứ 3. Bạn có thể chạy các model trực tiếp **trên máy tính của bạn**. Here is another example: - Original text: The model can then be **aligned** to the creator's preferences. For instance, a customer service chat model that must never be impolite to customers. - Translation: Model sau đó có thể được **alignment** (cân chỉnh) theo mong muốn của người tạo. Ví dụ: model chat hỗ trợ khách hàng không bao giờ được bất lịch sự. If the code block contains many plain texts, prove translation in collapsible
tag. Example: - Original text: ``` <|im_start|>Hello, how are you?<|im_end|> <|im_start|>I'm fine, thank you.<|im_end|> message = {{"user": "This is a test"}} ``` - Translation (add the
collapsible ABOVE of the original code block):
Bấm để xem bản dịch tiếng Việt ``` <|im_start|>Xin chào, bạn có khỏe không?<|im_end|> <|im_start|>Mình khỏe, cảm ơn bạn.<|im_end|> message = {{"user": "Đây là một tin nhắn thử"}} ```
``` <|im_start|>Hello, how are you?<|im_end|> <|im_start|>I'm fine, thank you.<|im_end|> message = {{"user": "This is a test"}} ``` IMPORTANT: Only output the translated text and nothing else, no need explanation or instruction. The input text is between "=== BEGIN OF TEXT ===" and "=== END OF TEXT ===". Please translate the following text to vietnamese: === BEGIN OF TEXT === {content} === END OF TEXT === '''.strip() auto_translate( prompt=prompt, output_lang=output_lang, ) ================================================ FILE: translation_agreements/ru/TRANSLATION_AGREEMENTS.md ================================================ ## Об организации процесса перевода в команде: 0. У нас Холакратия. Координатор команды - не менеджер! Он координирует работу команды. Чтобы все участники команды имели представление об общей картине, все ключевые моменты обсуждаются открыто в Issue. 1. Ставьте реальные сроки (если это возможно). Если это не возможно - не ставьте. Взятый вами блок - ваша ответственность, но вас никто не бросит. Не стесняйтесь спрашивать! 2. Если есть вопросы по применяемым инструментам, особенностям перевода - спрашивайте в Issue. 3. Старайтесь брать блоки для перевода последовательно. Тогда список эквивалентных слов будет максимально полезен. 4. Пополняйте список эквивалентных слов. Это упростит процесс перевода и существенно его ускорит. 5. Сообщения в commits и Pull Request в основной репозиторий курса пишите на английском языке. Это важно для последующей проверки PR. 6. Старайтесь не переводить по ночам) Хороша та работа, которую не нужно переделовать) ## Об использование вспомогательных средств (ИИ, нейронные сети, переводчики): 0. Можно и нужно! По другому сделать быстро и качественно - никак. К тому же будет забавно смотреться со стороны - перевод курса по ИИ без использования ИИ. Но обязательно проверьте свой перевод! Иногда там такая ахинея, ревьювер это сразу заметит))) 1. Если сомневаетесь в качестве, используйте альтернативный источник (например можно проверить перевод сделанный одним переводчиком с помощью другого, обсудить с командой). 2. Можно вообще ничего не использовать, если вы уверенны в своих знаниях английского и русского языка. Но в этом случае постарайтесь пожалуйста вначале выбирайте небольшие блоки для перевода. ## Соглашение по переводу: 1. Общепринятые в отрасли сокращения или аббревиатуры не переводится. За исключением случая введения нового термина и соответствующего ему сокращения. Как правило делается в определении. AI - ИИ LLM - БЯМ VLM - ЯМЗ 2. Нет смысла переводить тест используемый в примерах (в том числе на картинках, так как картинки мы не переводим). ***Пример:*** При предсказании следующего слова, не все слова в предложении одинаково важны; такие слова, как "France" и "capital" в предложении *"The capital of France is ..."*, несут наибольшую смысловую нагрузку. 3. Коментарии в примерах кода и ноутбуках переводим. 4. Для обеспечения единообразия перевода в случае работы нескольких переводчиков необходимо использовать приведенные ниже варианты перевода. Если встречаются сложные случаи употребления, то решение принимается в рамках конструктивной аргументированной дискуссии (не спора) с участием всех заинтересованных сторон. Наша цель - сделать качественный, максимально близкий к оригиналу перевод. | English Term | Russian Translation | Notes | |---|---|---| | Onboarding | Вводная часть | | | Optional | Необязательно | | | Live | Прямой эфир | | | Quick Quiz | Быстрый тест | | | Unit, section | Раздел | | | Tokens | Токены | | | Self-audit | Самооценка | | | Foundational Units | Фундаментальные разделы | | | Hands-on | Практические занятия | | | Hugging Face Spaces | Пространства (Spaces) Hugging Face | | | Use case assignments | Задания на применение | | | The Challenge | Соревнования | | | Leaderboard | Таблица результатов | | | Living project | Живой проект | | | Syllabus | Программа курса | | | Frameworks | Фреймворки | | | Use Cases | Примеры использования | | | Final Assignment | Итоговое задание | | | Benchmark | Бенчмарк | | | Acknowledgments | Благодарности | | | Chitchat | Свободное общение | | | Conversation | Диалог | | | Workflow | Рабочий процесс | | | Let’s dive in! | Погружаемся! | | | The Big Picture | Общая картина | | | Agency | Агентность | | | Vision Language Model | Языковая Модель Зрения (Vision Language Model) | см. п.п 1 соглашения по переводу | | Large Language Model | Большая Языковая Модель (Large Language Model) | см. п.п 1 соглашения по переводу | | Environment | Окружение | | | Intentional | Намеренными | | | Reasoning | Reasoning | | | Task | Задача (не задание!) | | | Processing | Предобработка (предварительная обработка, препроцессинг) | | | transformer | трансформер | | | dense representation | плотное векторное представление | | | Named Entity Recognition | Распознавание Именованных Сущностей (Named Entity Recognition, NER)| | | interactive playground | интерактивная демонстрация | | | input prompts | инструкции для ввода | Так как они определяют то, как будет обработанны входные данные (текст) | | wording | формулировка | | | self-supervised | самообучение | | | masked language modeling | маскированное языковое моделирование | | | unseen data | ранее не встречавщиеся данные | Звучит лучше, чем ранее не виденные данные) | | unsupervised learning | обучение без учителя | Стандарт | | supervised learning | обучение с учителем | Стандарт | | notebook | блокнот | Стандарт | | checkout | изучить | Зависит от контекста | | Instruct Model | Инструктивная модель | Более благозвучный вариант предложен @tixonsit | | tokenizer | Токенизатор | | | Generic | Универсальный | Зависит от контекста | | What You’ll Learn | Что вы узнаете | | | Implement | Имплементировать | | | instruct-tuned | инструктивно дообученная | Более благозвучный вариант предложен @tixonsit | | aligned | выровнена | Более благозвучный вариант предложен @tixonsit | | Low-Rank Adaptation of Large Language Models | Низкоранговая адаптация Больших Языковых Моделей | | | share | распространять | | | state-of-the-art | передовые | | | feedback | обратная связь | | ## Ревью перевода (список часто встречающихся проблем, за чем важно следить!): (в разработке, на основе предыдущих работ с Марией Халюсовой) 1. Качество перевода, обоснованное отклонение от оригинала. 2. Лишний пробел между концом предложения и точкой. (Данная ошибка часто возникает при использовании машинного перевода, либо работы над переводом ночью). 3. Часто забываем переводить текст в картинках (в примере ниже это `alt="Visual Gif of Attention"`). Пример: ``` Visual Gif of Attention ``` ================================================ FILE: units/en/_toctree.yml ================================================ - title: Unit 0. Welcome to the course sections: - local: unit0/introduction title: Welcome to the course 🤗 - local: unit0/onboarding title: Onboarding - local: unit0/discord101 title: (Optional) Discord 101 - title: Live 1. How the course works and Q&A sections: - local: communication/live1 title: Live 1. How the course works and Q&A - title: Unit 1. Introduction to Agents sections: - local: unit1/introduction title: Introduction - local: unit1/what-are-agents title: What is an Agent? - local: unit1/quiz1 title: Quick Quiz 1 - local: unit1/what-are-llms title: What are LLMs? - local: unit1/messages-and-special-tokens title: Messages and Special Tokens - local: unit1/tools title: What are Tools? - local: unit1/quiz2 title: Quick Quiz 2 - local: unit1/agent-steps-and-structure title: Understanding AI Agents through the Thought-Action-Observation Cycle - local: unit1/thoughts title: Thought, Internal Reasoning and the Re-Act Approach - local: unit1/actions title: Actions, Enabling the Agent to Engage with Its Environment - local: unit1/observations title: Observe, Integrating Feedback to Reflect and Adapt - local: unit1/dummy-agent-library title: Dummy Agent Library - local: unit1/tutorial title: Let’s Create Our First Agent Using smolagents - local: unit1/final-quiz title: Unit 1 Final Quiz - local: unit1/conclusion title: Conclusion - title: Unit 2. Frameworks for AI Agents sections: - local: unit2/introduction title: Frameworks for AI Agents - title: Unit 2.1 The smolagents framework sections: - local: unit2/smolagents/introduction title: Introduction to smolagents - local: unit2/smolagents/why_use_smolagents title: Why use smolagents? - local: unit2/smolagents/quiz1 title: Quick Quiz 1 - local: unit2/smolagents/code_agents title: Building Agents That Use Code - local: unit2/smolagents/tool_calling_agents title: Writing actions as code snippets or JSON blobs - local: unit2/smolagents/tools title: Tools - local: unit2/smolagents/retrieval_agents title: Retrieval Agents - local: unit2/smolagents/quiz2 title: Quick Quiz 2 - local: unit2/smolagents/multi_agent_systems title: Multi-Agent Systems - local: unit2/smolagents/vision_agents title: Vision and Browser agents - local: unit2/smolagents/final_quiz title: Final Quiz - local: unit2/smolagents/conclusion title: Conclusion - title: Unit 2.2 The LlamaIndex framework sections: - local: unit2/llama-index/introduction title: Introduction to LLamaIndex - local: unit2/llama-index/llama-hub title: Introduction to LlamaHub - local: unit2/llama-index/components title: What are Components in LlamaIndex? - local: unit2/llama-index/tools title: Using Tools in LlamaIndex - local: unit2/llama-index/quiz1 title: Quick Quiz 1 - local: unit2/llama-index/agents title: Using Agents in LlamaIndex - local: unit2/llama-index/workflows title: Creating Agentic Workflows in LlamaIndex - local: unit2/llama-index/quiz2 title: Quick Quiz 2 - local: unit2/llama-index/conclusion title: Conclusion - title: Unit 2.3 The LangGraph framework sections: - local: unit2/langgraph/introduction title: Introduction to LangGraph - local: unit2/langgraph/when_to_use_langgraph title: What is LangGraph? - local: unit2/langgraph/building_blocks title: Building Blocks of LangGraph - local: unit2/langgraph/first_graph title: Building Your First LangGraph - local: unit2/langgraph/document_analysis_agent title: Document Analysis Graph - local: unit2/langgraph/quiz1 title: Quick Quiz 1 - local: unit2/langgraph/conclusion title: Conclusion - title: Unit 3. Use Case for Agentic RAG sections: - local: unit3/agentic-rag/introduction title: Introduction to Use Case for Agentic RAG - local: unit3/agentic-rag/agentic-rag title: Agentic Retrieval Augmented Generation (RAG) - local: unit3/agentic-rag/invitees title: Creating a RAG Tool for Guest Stories - local: unit3/agentic-rag/tools title: Building and Integrating Tools for Your Agent - local: unit3/agentic-rag/agent title: Creating Your Gala Agent - local: unit3/agentic-rag/conclusion title: Conclusion - title: Unit 4. Final Project - Create, Test, and Certify Your Agent sections: - local: unit4/introduction title: Introduction to the Final Unit - local: unit4/what-is-gaia title: What is GAIA? - local: unit4/hands-on title: The Final Hands-On - local: unit4/get-your-certificate title: Get Your Certificate Of Excellence - local: unit4/conclusion title: Conclusion of the Course - local: unit4/additional-readings title: What Should You Learn Now? - title: Bonus Unit 1. Fine-tuning an LLM for Function-calling sections: - local: bonus-unit1/introduction title: Introduction - local: bonus-unit1/what-is-function-calling title: What is Function Calling? - local: bonus-unit1/fine-tuning title: Let's Fine-Tune your model for Function-calling - local: bonus-unit1/conclusion title: Conclusion - title: Bonus Unit 2. Agent Observability and Evaluation sections: - local: bonus-unit2/introduction title: Introduction - local: bonus-unit2/what-is-agent-observability-and-evaluation title: What is agent observability and evaluation? - local: bonus-unit2/monitoring-and-evaluating-agents-notebook title: Monitoring and evaluating agents - local: bonus-unit2/quiz title: Quiz - title: Bonus Unit 3. Agents in Games with Pokemon sections: - local: bonus-unit3/introduction title: Introduction - local: bonus-unit3/state-of-art title: The State of the Art in Using LLMs in Games - local: bonus-unit3/from-llm-to-agents title: From LLMs to AI Agents - local: bonus-unit3/building_your_pokemon_agent title: Build Your Own Pokémon Battle Agent - local: bonus-unit3/launching_agent_battle title: Launching Your Pokémon Battle Agent - local: bonus-unit3/conclusion title: Conclusion ================================================ FILE: units/en/bonus-unit1/conclusion.mdx ================================================ # Conclusion [[conclusion]] Congratulations on finishing this first Bonus Unit 🥳 You've just **mastered understanding function-calling and how to fine-tune your model to do function-calling**! If we have one piece of advice now, it’s to try to **fine-tune different models**. The **best way to learn is by trying.** In the next Unit, you're going to learn how to use **state-of-the-art frameworks such as `smolagents`, `LlamaIndex` and `LangGraph`**. Finally, we would love **to hear what you think of the course and how we can improve it**. If you have some feedback then, please 👉 [fill this form](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ### Keep Learning, Stay Awesome 🤗 ================================================ FILE: units/en/bonus-unit1/fine-tuning.mdx ================================================ # Let's Fine-Tune Your Model for Function-Calling We're now ready to fine-tune our first model for function-calling 🔥. ## How do we train our model for function-calling? > Answer: We need **data** A model training process can be divided into 3 steps: 1. **The model is pre-trained on a large quantity of data**. The output of that step is a **pre-trained model**. For instance, [google/gemma-2-2b](https://huggingface.co/google/gemma-2-2b). It's a base model and only knows how **to predict the next token without strong instruction following capabilities**. 2. To be useful in a chat context, the model then needs to be **fine-tuned** to follow instructions. In this step, it can be trained by model creators, the open-source community, you, or anyone. For instance, [google/gemma-2-2b-it](https://huggingface.co/google/gemma-2-2b-it) is an instruction-tuned model by the Google Team behind the Gemma project. 3. The model can then be **aligned** to the creator's preferences. For instance, a customer service chat model that must never be impolite to customers. Usually a complete product like Gemini or Mistral **will go through all 3 steps**, whereas the models you can find on Hugging Face have completed one or more steps of this training. In this tutorial, we will build a function-calling model based on [google/gemma-2-2b-it](https://huggingface.co/google/gemma-2-2b-it). We choose the fine-tuned model [google/gemma-2-2b-it](https://huggingface.co/google/gemma-2-2b-it) instead of the base model [google/gemma-2-2b](https://huggingface.co/google/gemma-2-2b) because the fine-tuned model has been improved for our use-case. Starting from the pre-trained model **would require more training in order to learn instruction following, chat AND function-calling**. By starting from the instruction-tuned model, **we minimize the amount of information that our model needs to learn**. ## LoRA (Low-Rank Adaptation of Large Language Models) LoRA is a popular and lightweight training technique that significantly **reduces the number of trainable parameters**. It works by **inserting a smaller number of new weights as an adapter into the model to train**. This makes training with LoRA much faster, memory-efficient, and produces smaller model weights (a few hundred MBs), which are easier to store and share. LoRA inference LoRA works by adding pairs of rank decomposition matrices to Transformer layers, typically focusing on linear layers. During training, we will "freeze" the rest of the model and will only update the weights of those newly added adapters. By doing so, the number of **parameters** that we need to train drops considerably as we only need to update the adapter's weights. During inference, the input is passed into the adapter and the base model, or these adapter weights can be merged with the base model, resulting in no additional latency overhead. LoRA is particularly useful for adapting **large** language models to specific tasks or domains while keeping resource requirements manageable. This helps reduce the memory **required** to train a model. If you want to learn more about how LoRA works, you should check out this [tutorial](https://huggingface.co/learn/nlp-course/chapter11/4?fw=pt). ## Fine-Tuning a Model for Function-Calling You can access the tutorial notebook 👉 [here](https://huggingface.co/agents-course/notebooks/blob/main/bonus-unit1/bonus-unit1.ipynb). Then, click on [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/#fileId=https://huggingface.co/agents-course/notebooks/blob/main/bonus-unit1/bonus-unit1.ipynb) to be able to run it in a Colab Notebook. ================================================ FILE: units/en/bonus-unit1/introduction.mdx ================================================ # Introduction ![Bonus Unit 1 Thumbnail](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit1/thumbnail.jpg) Welcome to this first **Bonus Unit**, where you'll learn to **fine-tune a Large Language Model (LLM) for function calling**. In terms of LLMs, function calling is quickly becoming a *must-know* technique. The idea is, rather than relying only on prompt-based approaches like we did in Unit 1, function calling trains your model to **take actions and interpret observations during the training phase**, making your AI more robust. > **When should I do this Bonus Unit?** > > This section is **optional** and is more advanced than Unit 1, so don't hesitate to either do this unit now or revisit it when your knowledge has improved thanks to this course. > > But don't worry, this Bonus Unit is designed to have all the information you need, so we'll walk you through every core concept of fine-tuning a model for function-calling even if you haven’t learned yet the inner workings of fine-tuning. The best way for you to be able to follow this Bonus Unit is: 1. Know how to Fine-Tune an LLM with Transformers, if it's not the case [check this](https://huggingface.co/learn/nlp-course/chapter3/1?fw=pt). 2. Know how to use `SFTTrainer` to fine-tune our model, to learn more about it [check this documentation](https://huggingface.co/learn/nlp-course/en/chapter11/1). --- ## What You’ll Learn 1. **Function Calling** How modern LLMs structure their conversations effectively letting them trigger **Tools**. 2. **LoRA (Low-Rank Adaptation)** A **lightweight and efficient** fine-tuning method that cuts down on computational and storage overhead. LoRA makes training large models *faster, cheaper, and easier* to deploy. 3. **The Thought → Act → Observe Cycle** in Function Calling models A simple but powerful approach for structuring how your model decides when (and how) to call functions, track intermediate steps, and interpret the results from external Tools or APIs. 4. **New Special Tokens** We’ll introduce **special markers** that help the model distinguish between: - Internal “chain-of-thought” reasoning - Outgoing function calls - Responses coming back from external tools --- By the end of this bonus unit, you’ll be able to: - **Understand** the inner working of APIs when it comes to Tools. - **Fine-tune** a model using the LoRA technique. - **Implement** and **modify** the Thought → Act → Observe cycle to create robust and maintainable Function-calling workflows. - **Design and utilize** special tokens to seamlessly separate the model’s internal reasoning from its external actions. And you'll **have fine-tuned your own model to do function calling.** 🔥 Let’s dive into **function calling**! ================================================ FILE: units/en/bonus-unit1/what-is-function-calling.mdx ================================================ # What is Function Calling? Function-calling is a **way for an LLM to take actions on its environment**. It was first [introduced in GPT-4](https://openai.com/index/function-calling-and-other-api-updates/), and was later reproduced in other models. Just like the tools of an Agent, function-calling gives the model the capacity to **take an action on its environment**. However, the function calling capacity **is learned by the model**, and relies **less on prompting than other agents techniques**. During Unit 1, the Agent **didn't learn to use the Tools**, we just provided the list, and we relied on the fact that the model **was able to generalize on defining a plan using these Tools**. While here, **with function-calling, the Agent is fine-tuned (trained) to use Tools**. ## How does the model "learn" to take an action? In Unit 1, we explored the general workflow of an agent. Once the user has given some tools to the agent and prompted it with a query, the model will cycle through: 1. *Think* : What action(s) do I need to take in order to fulfill the objective. 2. *Act* : Format the action with the correct parameter and stop the generation. 3. *Observe* : Get back the result from the execution. In a "typical" conversation with a model through an API, the conversation will alternate between user and assistant messages like this: ```python conversation = [ {"role": "user", "content": "I need help with my order"}, {"role": "assistant", "content": "I'd be happy to help. Could you provide your order number?"}, {"role": "user", "content": "It's ORDER-123"}, ] ``` Function-calling brings **new roles to the conversation**! 1. One new role for an **Action** 2. One new role for an **Observation** If we take the [Mistral API](https://docs.mistral.ai/capabilities/function_calling/) as an example, it would look like this: ```python conversation = [ { "role": "user", "content": "What's the status of my transaction T1001?" }, { "role": "assistant", "content": "", "function_call": { "name": "retrieve_payment_status", "arguments": "{\"transaction_id\": \"T1001\"}" } }, { "role": "tool", "name": "retrieve_payment_status", "content": "{\"status\": \"Paid\"}" }, { "role": "assistant", "content": "Your transaction T1001 has been successfully paid." } ] ``` > ... But you said there's a new role for function calls? **Yes and no**, in this case and in a lot of other APIs, the model formats the action to take as an "assistant" message. The chat template will then represent this as **special tokens** for function-calling. - `[AVAILABLE_TOOLS]` – Start the list of available tools - `[/AVAILABLE_TOOLS]` – End the list of available tools - `[TOOL_CALLS]` – Make a call to a tool (i.e., take an "Action") - `[TOOL_RESULTS]` – "Observe" the result of the action - `[/TOOL_RESULTS]` – End of the observation (i.e., the model can decode again) We'll talk again about function-calling in this course, but if you want to dive deeper you can check [this excellent documentation section](https://docs.mistral.ai/capabilities/function_calling/). --- Now that we learned what function-calling is and how it works, let's **add some function-calling capabilities to a model that does not have those capacities yet**: [google/gemma-2-2b-it](https://huggingface.co/google/gemma-2-2b-it), by appending some new special tokens to the model. To be able to do that, **we need first to understand fine-tuning and LoRA**. ================================================ FILE: units/en/bonus-unit2/introduction.mdx ================================================ # AI Agent Observability & Evaluation ![Bonus Unit 2 Thumbnail](https://langfuse.com/images/cookbook/huggingface-agent-course/agent-observability-and-evaluation.png) Welcome to **Bonus Unit 2**! In this chapter, you'll explore advanced strategies for observing, evaluating, and ultimately improving the performance of your agents. --- ## 📚 When Should I Do This Bonus Unit? This bonus unit is perfect if you: - **Develop and Deploy AI Agents:** You want to ensure that your agents are performing reliably in production. - **Need Detailed Insights:** You're looking to diagnose issues, optimize performance, or understand the inner workings of your agent. - **Aim to Reduce Operational Overhead:** By monitoring agent costs, latency, and execution details, you can efficiently manage resources. - **Seek Continuous Improvement:** You’re interested in integrating both real-time user feedback and automated evaluation into your AI applications. In short, for everyone who wants to bring their agents in front of users! --- ## 🤓 What You’ll Learn In this unit, you'll learn: - **Instrument Your Agent:** Learn how to integrate observability tools via OpenTelemetry with the *smolagents* framework. - **Monitor Metrics:** Track performance indicators such as token usage (costs), latency, and error traces. - **Evaluate in Real-Time:** Understand techniques for live evaluation, including gathering user feedback and leveraging an LLM-as-a-judge. - **Offline Analysis:** Use benchmark datasets (e.g., GSM8K) to test and compare agent performance. --- ## 🚀 Ready to Get Started? In the next section, you'll learn the basics of Agent Observability and Evaluation. After that, its time to see it in action! ================================================ FILE: units/en/bonus-unit2/monitoring-and-evaluating-agents-notebook.mdx ================================================ # Bonus Unit 2: Observability and Evaluation of Agents > [!TIP] > You can follow the code in this notebook that you can run using Google Colab. In this notebook, we will learn how to **monitor the internal steps (traces) of our AI agent** and **evaluate its performance** using open-source observability tools. The ability to observe and evaluate an agent’s behavior is essential for: - Debugging issues when tasks fail or produce suboptimal results - Monitoring costs and performance in real-time - Improving reliability and safety through continuous feedback ## Exercise Prerequisites 🏗️ Before running this notebook, please be sure you have: 🔲 📚 **Studied** [Introduction to Agents](https://huggingface.co/learn/agents-course/unit1/introduction) 🔲 📚 **Studied** [The smolagents framework](https://huggingface.co/learn/agents-course/unit2/smolagents/introduction) ## Step 0: Install the Required Libraries We will need a few libraries that allow us to run, monitor, and evaluate our agents: ```python %pip install langfuse 'smolagents[telemetry]' openinference-instrumentation-smolagents datasets 'smolagents[gradio]' gradio --upgrade ``` ## Step 1: Instrument Your Agent In this notebook, we will use [Langfuse](https://langfuse.com/) as our observability tool, but you can use **any other OpenTelemetry-compatible service**. The code below shows how to set environment variables for Langfuse (or any OTel endpoint) and how to instrument your smolagent. **Note:** If you are using LlamaIndex or LangGraph, you can find documentation on instrumenting them [here](https://langfuse.com/docs/integrations/llama-index/workflows) and [here](https://langfuse.com/docs/integrations/langchain/example-python-langgraph). First, let's set up the Langfuse credentials as environment variables. Get your Langfuse API keys by signing up for [Langfuse Cloud](https://cloud.langfuse.com) or [self-hosting Langfuse](https://langfuse.com/self-hosting). ```python import os # Get keys for your project from the project settings page: https://cloud.langfuse.com os.environ["LANGFUSE_PUBLIC_KEY"] = "pk-lf-..." os.environ["LANGFUSE_SECRET_KEY"] = "sk-lf-..." os.environ["LANGFUSE_HOST"] = "https://cloud.langfuse.com" # 🇪🇺 EU region # os.environ["LANGFUSE_HOST"] = "https://us.cloud.langfuse.com" # 🇺🇸 US region ``` We also need to configure our Hugging Face token for inference calls. ```python # Set your Hugging Face and other tokens/secrets as environment variable os.environ["HF_TOKEN"] = "hf_..." ``` With the environment variables set, we can now initialize the Langfuse client. `get_client()` initializes the Langfuse client using the credentials provided in the environment variables. ```python from langfuse import get_client langfuse = get_client() # Verify connection if langfuse.auth_check(): print("Langfuse client is authenticated and ready!") else: print("Authentication failed. Please check your credentials and host.") ``` Next, we can set up the `SmolagentsInstrumentor()` to instrument our smolagent and send traces to Langfuse. ```python from openinference.instrumentation.smolagents import SmolagentsInstrumentor SmolagentsInstrumentor().instrument() ``` ## Step 2: Test Your Instrumentation Here is a simple CodeAgent from smolagents that calculates `1+1`. We run it to confirm that the instrumentation is working correctly. If everything is set up correctly, you will see logs/spans in your observability dashboard. ```python from smolagents import InferenceClientModel, CodeAgent # Create a simple agent to test instrumentation agent = CodeAgent( tools=[], model=InferenceClientModel() ) agent.run("1+1=") ``` Check your [Langfuse Traces Dashboard](https://cloud.langfuse.com) (or your chosen observability tool) to confirm that the spans and logs have been recorded. Example screenshot from Langfuse: ![Example trace in Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/first-example-trace.png) _[Link to the trace](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/1b94d6888258e0998329cdb72a371155?timestamp=2025-03-10T11%3A59%3A41.743Z)_ ## Step 3: Observe and Evaluate a More Complex Agent Now that you have confirmed your instrumentation works, let's try a more complex query so we can see how advanced metrics (token usage, latency, costs, etc.) are tracked. ```python from smolagents import (CodeAgent, DuckDuckGoSearchTool, InferenceClientModel) search_tool = DuckDuckGoSearchTool() agent = CodeAgent(tools=[search_tool], model=InferenceClientModel()) agent.run("How many Rubik's Cubes could you fit inside the Notre Dame Cathedral?") ``` ### Trace Structure Most observability tools record a **trace** that contains **spans**, which represent each step of your agent’s logic. Here, the trace contains the overall agent run and sub-spans for: - The tool calls (DuckDuckGoSearchTool) - The LLM calls (InferenceClientModel) You can inspect these to see precisely where time is spent, how many tokens are used, and so on: ![Trace tree in Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/trace-tree.png) _[Link to the trace](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/1ac33b89ffd5e75d4265b62900c348ed?timestamp=2025-03-07T13%3A45%3A09.149Z&display=preview)_ ## Online Evaluation In the previous section, we learned about the difference between online and offline evaluation. Now, we will see how to monitor your agent in production and evaluate it live. ### Common Metrics to Track in Production 1. **Costs** — The smolagents instrumentation captures token usage, which you can transform into approximate costs by assigning a price per token. 2. **Latency** — Observe the time it takes to complete each step, or the entire run. 3. **User Feedback** — Users can provide direct feedback (thumbs up/down) to help refine or correct the agent. 4. **LLM-as-a-Judge** — Use a separate LLM to evaluate your agent’s output in near real-time (e.g., checking for toxicity or correctness). Below, we show examples of these metrics. #### 1. Costs Below is a screenshot showing usage for `Qwen2.5-Coder-32B-Instruct` calls. This is useful to see costly steps and optimize your agent. ![Costs](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/smolagents-costs.png) _[Link to the trace](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/1ac33b89ffd5e75d4265b62900c348ed?timestamp=2025-03-07T13%3A45%3A09.149Z&display=preview)_ #### 2. Latency We can also see how long it took to complete each step. In the example below, the entire conversation took 32 seconds, which you can break down by step. This helps you identify bottlenecks and optimize your agent. ![Latency](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/smolagents-latency.png) _[Link to the trace](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/1ac33b89ffd5e75d4265b62900c348ed?timestamp=2025-03-07T13%3A45%3A09.149Z&display=preview)_ #### 3. Additional Attributes You may also pass additional attributes to your spans. These can include `user_id`, `tags`, `session_id`, and custom metadata. Enriching traces with these details is important for analysis, debugging, and monitoring of your application’s behavior across different users or sessions. ```python from smolagents import (CodeAgent, DuckDuckGoSearchTool, InferenceClientModel) search_tool = DuckDuckGoSearchTool() agent = CodeAgent( tools=[search_tool], model=InferenceClientModel() ) with langfuse.start_as_current_span( name="Smolagent-Trace", ) as span: # Run your application here response = agent.run("What is the capital of Germany?") # Pass additional attributes to the span span.update_trace( input="What is the capital of Germany?", output=response, user_id="smolagent-user-123", session_id="smolagent-session-123456789", tags=["city-question", "testing-agents"], metadata={"email": "user@langfuse.com"}, ) # Flush events in short-lived applications langfuse.flush() ``` ![Enhancing agent runs with additional metrics](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/smolagents-attributes.png) #### 4. User Feedback If your agent is embedded into a user interface, you can record direct user feedback (like a thumbs-up/down in a chat UI). Below is an example using [Gradio](https://gradio.app/) to embed a chat with a simple feedback mechanism. In the code snippet below, when a user sends a chat message, we capture the trace in Langfuse. If the user likes/dislikes the last answer, we attach a score to the trace. ```python import gradio as gr from smolagents import (CodeAgent, InferenceClientModel) from langfuse import get_client langfuse = get_client() model = InferenceClientModel() agent = CodeAgent(tools=[], model=model, add_base_tools=True) trace_id = None def respond(prompt, history): with langfuse.start_as_current_span( name="Smolagent-Trace"): # Run your application here output = agent.run(prompt) global trace_id trace_id = langfuse.get_current_trace_id() history.append({"role": "assistant", "content": str(output)}) return history def handle_like(data: gr.LikeData): # For demonstration, we map user feedback to a 1 (like) or 0 (dislike) if data.liked: langfuse.create_score( value=1, name="user-feedback", trace_id=trace_id ) else: langfuse.create_score( value=0, name="user-feedback", trace_id=trace_id ) with gr.Blocks() as demo: chatbot = gr.Chatbot(label="Chat", type="messages") prompt_box = gr.Textbox(placeholder="Type your message...", label="Your message") # When the user presses 'Enter' on the prompt, we run 'respond' prompt_box.submit( fn=respond, inputs=[prompt_box, chatbot], outputs=chatbot ) # When the user clicks a 'like' button on a message, we run 'handle_like' chatbot.like(handle_like, None, None) demo.launch() ``` User feedback is then captured in your observability tool: ![User feedback is being captured in Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/user-feedback-gradio.png) #### 5. LLM-as-a-Judge LLM-as-a-Judge is another way to automatically evaluate your agent's output. You can set up a separate LLM call to gauge the output’s correctness, toxicity, style, or any other criteria you care about. **Workflow**: 1. You define an **Evaluation Template**, e.g., "Check if the text is toxic." 2. Each time your agent generates output, you pass that output to your "judge" LLM with the template. 3. The judge LLM responds with a rating or label that you log to your observability tool. Example from Langfuse: ![LLM-as-a-Judge Evaluation Template](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/evaluator-template.png) ![LLM-as-a-Judge Evaluator](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/evaluator.png) ```python # Example: Checking if the agent’s output is toxic or not. from smolagents import (CodeAgent, DuckDuckGoSearchTool, InferenceClientModel) search_tool = DuckDuckGoSearchTool() agent = CodeAgent(tools=[search_tool], model=InferenceClientModel()) agent.run("Can eating carrots improve your vision?") ``` You can see that the answer of this example is judged as "not toxic". ![LLM-as-a-Judge Evaluation Score](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/llm-as-a-judge-score.png) #### 6. Observability Metrics Overview All of these metrics can be visualized together in dashboards. This enables you to quickly see how your agent performs across many sessions and helps you to track quality metrics over time. ![Observability metrics overview](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/langfuse-dashboard.png) ## Offline Evaluation Online evaluation is essential for live feedback, but you also need **offline evaluation**—systematic checks before or during development. This helps maintain quality and reliability before rolling changes into production. ### Dataset Evaluation In offline evaluation, you typically: 1. Have a benchmark dataset (with prompt and expected output pairs) 2. Run your agent on that dataset 3. Compare outputs to the expected results or use an additional scoring mechanism Below, we demonstrate this approach with the [GSM8K dataset](https://huggingface.co/datasets/openai/gsm8k), which contains math questions and solutions. ```python import pandas as pd from datasets import load_dataset # Fetch GSM8K from Hugging Face dataset = load_dataset("openai/gsm8k", 'main', split='train') df = pd.DataFrame(dataset) print("First few rows of GSM8K dataset:") print(df.head()) ``` Next, we create a dataset entity in Langfuse to track the runs. Then, we add each item from the dataset to the system. (If you’re not using Langfuse, you might simply store these in your own database or local file for analysis.) ```python from langfuse import get_client langfuse = get_client() langfuse_dataset_name = "gsm8k_dataset_huggingface" # Create a dataset in Langfuse langfuse.create_dataset( name=langfuse_dataset_name, description="GSM8K benchmark dataset uploaded from Huggingface", metadata={ "date": "2025-03-10", "type": "benchmark" } ) ``` ```python for idx, row in df.iterrows(): langfuse.create_dataset_item( dataset_name=langfuse_dataset_name, input={"text": row["question"]}, expected_output={"text": row["answer"]}, metadata={"source_index": idx} ) if idx >= 9: # Upload only the first 10 items for demonstration break ``` ![Dataset items in Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/example-dataset.png) #### Running the Agent on the Dataset We define a helper function `run_smolagent()` that: 1. Starts a Langfuse span 2. Runs our agent on the prompt 3. Records the trace ID in Langfuse Then, we loop over each dataset item, run the agent, and link the trace to the dataset item. We can also attach a quick evaluation score if desired. ```python from opentelemetry.trace import format_trace_id from smolagents import (CodeAgent, InferenceClientModel, LiteLLMModel) from langfuse import get_client langfuse = get_client() # Example: using InferenceClientModel or LiteLLMModel to access openai, anthropic, gemini, etc. models: model = InferenceClientModel() agent = CodeAgent( tools=[], model=model, add_base_tools=True ) dataset_name = "gsm8k_dataset_huggingface" current_run_name = "smolagent-notebook-run-01" # Identifies this specific evaluation run # Assume 'run_smolagent' is your instrumented application function def run_smolagent(question): with langfuse.start_as_current_generation(name="qna-llm-call") as generation: # Simulate LLM call result = agent.run(question) # Update the trace with the input and output generation.update_trace( input= question, output=result, ) return result dataset = langfuse.get_dataset(name=dataset_name) # Fetch your pre-populated dataset for item in dataset.items: # Use the item.run() context manager with item.run( run_name=current_run_name, run_metadata={"model_provider": "Hugging Face", "temperature_setting": 0.7}, run_description="Evaluation run for GSM8K dataset" ) as root_span: # root_span is the root span of the new trace for this item and run. # All subsequent langfuse operations within this block are part of this trace. # Call your application logic generated_answer = run_smolagent(question=item.input["text"]) print(item.input) ``` You can repeat this process with different: - Models (OpenAI GPT, local LLM, etc.) - Tools (search vs. no search) - Prompts (different system messages) Then compare them side-by-side in your observability tool: ![Dataset run overview](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/dataset_runs.png) ![Dataset run comparison](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/dataset-run-comparison.png) ## Final Thoughts In this notebook, we covered how to: 1. **Set up Observability** using smolagents + OpenTelemetry exporters 2. **Check Instrumentation** by running a simple agent 3. **Capture Detailed Metrics** (cost, latency, etc.) through an observability tools 4. **Collect User Feedback** via a Gradio interface 5. **Use LLM-as-a-Judge** to automatically evaluate outputs 6. **Perform Offline Evaluation** with a benchmark dataset 🤗 Happy coding! ================================================ FILE: units/en/bonus-unit2/quiz.mdx ================================================ # Quiz: Evaluating AI Agents Let's assess your understanding of the agent tracing and evaluation concepts covered in this bonus unit. This quiz is optional and ungraded. ### Q1: What does observability in AI agents primarily refer to? Which statement accurately describes the purpose of observability for AI agents? ### Q2: Which of the following is NOT a common metric monitored in agent observability? Select the metric that does not typically fall under the observability umbrella. ### Q3: What best describes offline evaluation of an AI agent? Determine the statement that correctly captures the essence of offline evaluation. ### Q4: Which advantage does online evaluation of agents offer? Pick the statement that best reflects the benefit of online evaluation. ### Q5: What role does OpenTelemetry play in AI agent observability and evaluation? Which statement best describes the role of OpenTelemetry in monitoring AI agents? Congratulations on completing this quiz! 🎉 If you missed any questions, consider reviewing the content of this bonus unit for a deeper understanding. If you did well, you're ready to explore more advanced topics in agent observability and evaluation! ================================================ FILE: units/en/bonus-unit2/what-is-agent-observability-and-evaluation.mdx ================================================ # AI Agent Observability and Evaluation ## 🔎 What is Observability? Observability is about understanding what's happening inside your AI agent by looking at external signals like logs, metrics, and traces. For AI agents, this means tracking actions, tool usage, model calls, and responses to debug and improve agent performance. ![Observability dashboard](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/langfuse-dashboard.png) ## 🔭 Why Agent Observability Matters Without observability, AI agents are "black boxes." Observability tools make agents transparent, enabling you to: - Understand costs and accuracy trade-offs - Measure latency - Detect harmful language & prompt injection - Monitor user feedback In other words, it makes your demo agent ready for production! ## 🔨 Observability Tools Common observability tools for AI agents include platforms like [Langfuse](https://langfuse.com) and [Arize](https://www.arize.com). These tools help collect detailed traces and offer dashboards to monitor metrics in real-time, making it easy to detect problems and optimize performance. Observability tools vary widely in their features and capabilities. Some tools are open source, benefiting from large communities that shape their roadmaps and extensive integrations. Additionally, certain tools specialize in specific aspects of LLMOps—such as observability, evaluations, or prompt management—while others are designed to cover the entire LLMOps workflow. We encourage you to explore the documentation of different options to pick a solution that works well for you. Many agent frameworks such as [smolagents](https://huggingface.co/docs/smolagents/v1.12.0/en/index) use the [OpenTelemetry](https://opentelemetry.io/docs/) standard to expose metadata to the observability tools. In addition to this, observability tools build custom instrumentations to allow for more flexibility in the fast moving world of LLMs. You should check the documentation of the tool you are using to see what is supported. ## 🔬Traces and Spans Observability tools usually represent agent runs as traces and spans. - **Traces** represent a complete agent task from start to finish (like handling a user query). - **Spans** are individual steps within the trace (like calling a language model or retrieving data). ![Example of a smolagent trace in Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/trace-tree.png) ## 📊 Key Metrics to Monitor Here are some of the most common metrics that observability tools monitor: **Latency:** How quickly does the agent respond? Long waiting times negatively impact user experience. You should measure latency for tasks and individual steps by tracing agent runs. For example, an agent that takes 20 seconds for all model calls could be accelerated by using a faster model or by running model calls in parallel. **Costs:** What’s the expense per agent run? AI agents rely on LLM calls billed per token or external APIs. Frequent tool usage or multiple prompts can rapidly increase costs. For instance, if an agent calls an LLM five times for marginal quality improvement, you must assess if the cost is justified or if you could reduce the number of calls or use a cheaper model. Real-time monitoring can also help identify unexpected spikes (e.g., bugs causing excessive API loops). **Request Errors:** How many requests did the agent fail? This can include API errors or failed tool calls. To make your agent more robust against these in production, you can then set up fallbacks or retries. E.g. if LLM provider A is down, you switch to LLM provider B as backup. **User Feedback:** Implementing direct user evaluations provide valuable insights. This can include explicit ratings (👍thumbs-up/👎down, ⭐1-5 stars) or textual comments. Consistent negative feedback should alert you as this is a sign that the agent is not working as expected. **Implicit User Feedback:** User behaviors provide indirect feedback even without explicit ratings. This can include immediate question rephrasing, repeated queries or clicking a retry button. E.g. if you see that users repeatedly ask the same question, this is a sign that the agent is not working as expected. **Accuracy:** How frequently does the agent produce correct or desirable outputs? Accuracy definitions vary (e.g., problem-solving correctness, information retrieval accuracy, user satisfaction). The first step is to define what success looks like for your agent. You can track accuracy via automated checks, evaluation scores, or task completion labels. For example, marking traces as "succeeded" or "failed". **Automated Evaluation Metrics:** You can also set up automated evals. For instance, you can use an LLM to score the output of the agent e.g. if it is helpful, accurate, or not. There are also several open source libraries that help you to score different aspects of the agent. E.g. [RAGAS](https://docs.ragas.io/) for RAG agents or [LLM Guard](https://llm-guard.com/) to detect harmful language or prompt injection. In practice, a combination of these metrics gives the best coverage of an AI agent’s health. In this chapters [example notebook](https://colab.research.google.com/#fileId=https://huggingface.co/agents-course/notebooks/blob/main/bonus-unit2/monitoring-and-evaluating-agents.ipynb), we'll show you how these metrics looks in real examples but first, we'll learn how a typical evaluation workflow looks like. ## 👍 Evaluating AI Agents Observability gives us metrics, but evaluation is the process of analyzing that data (and performing tests) to determine how well an AI agent is performing and how it can be improved. In other words, once you have those traces and metrics, how do you use them to judge the agent and make decisions? Regular evaluation is important because AI agents are often non-deterministic and can evolve (through updates or drifting model behavior) – without evaluation, you wouldn’t know if your “smart agent” is actually doing its job well or if it’s regressed. There are two categories of evaluations for AI agents: **online evaluation** and **offline evaluation**. Both are valuable, and they complement each other. We usually begin with offline evaluation, as this is the minimum necessary step before deploying any agent. ### 🥷 Offline Evaluation ![Dataset items in Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/example-dataset.png) This involves evaluating the agent in a controlled setting, typically using test datasets, not live user queries. You use curated datasets where you know what the expected output or correct behavior is, and then run your agent on those. For instance, if you built a math word-problem agent, you might have a [test dataset](https://huggingface.co/datasets/gsm8k) of 100 problems with known answers. Offline evaluation is often done during development (and can be part of CI/CD pipelines) to check improvements or guard against regressions. The benefit is that it’s **repeatable and you can get clear accuracy metrics since you have ground truth**. You might also simulate user queries and measure the agent’s responses against ideal answers or use automated metrics as described above. The key challenge with offline eval is ensuring your test dataset is comprehensive and stays relevant – the agent might perform well on a fixed test set but encounter very different queries in production. Therefore, you should keep test sets updated with new edge cases and examples that reflect real-world scenarios​. A mix of small “smoke test” cases and larger evaluation sets is useful: small sets for quick checks and larger ones for broader performance metrics​. ### 🔄 Online Evaluation This refers to evaluating the agent in a live, real-world environment, i.e. during actual usage in production. Online evaluation involves monitoring the agent’s performance on real user interactions and analyzing outcomes continuously. For example, you might track success rates, user satisfaction scores, or other metrics on live traffic. The advantage of online evaluation is that it **captures things you might not anticipate in a lab setting** – you can observe model drift over time (if the agent’s effectiveness degrades as input patterns shift) and catch unexpected queries or situations that weren’t in your test data​. It provides a true picture of how the agent behaves in the wild. Online evaluation often involves collecting implicit and explicit user feedback, as discussed, and possibly running shadow tests or A/B tests (where a new version of the agent runs in parallel to compare against the old). The challenge is that it can be tricky to get reliable labels or scores for live interactions – you might rely on user feedback or downstream metrics (like did the user click the result). ### 🤝 Combining the two In practice, successful AI agent evaluation blends **online** and **offline** methods​. You might run regular offline benchmarks to quantitatively score your agent on defined tasks and continuously monitor live usage to catch things the benchmarks miss. For example, offline tests can catch if a code-generation agent’s success rate on a known set of problems is improving, while online monitoring might alert you that users have started asking a new category of question that the agent struggles with. Combining both gives a more robust picture. In fact, many teams adopt a loop: _offline evaluation → deploy new agent version → monitor online metrics and collect new failure examples → add those examples to offline test set → iterate_. This way, evaluation is continuous and ever-improving. ## 🧑‍💻 Lets see how this works in practice In the next section, we'll see examples of how we can use observability tools to monitor and evaluate our agent. ================================================ FILE: units/en/bonus-unit3/building_your_pokemon_agent.mdx ================================================ # Build Your Own Pokémon Battle Agent Now that you’ve explored the potential and limitations of Agentic AI in games, it’s time to get hands-on. In this section, you’ll **build your very own AI Agent to battle in Pokémon-style turn-based combat**, using everything you’ve learned throughout the course. We’ll break the system into four key building blocks: - **Poke-env:** A Python library designed to train rule-based or reinforcement learning Pokémon bots. - **Pokémon Showdown:** An online battle simulator where your agent will fight. - **LLMAgentBase:** A custom Python class we’ve built to connect your LLM with the Poke-env battle environment. - **TemplateAgent:** A starter template you’ll complete to create your own unique battle agent. Let’s explore each of these components in more detail. ## 🧠 Poke-env ![Battle gif](https://github.com/hsahovic/poke-env/raw/master/rl-gif.gif) [Poke-env](https://github.com/hsahovic/poke-env) is a Python interface originally built for training reinforcement learning bots by [Haris Sahovic](https://huggingface.co/hsahovic), but we’ve repurposed it for Agentic AI. It allows your agent to interact with Pokémon Showdown through a simple API. It provides a `Player` class from which your Agent will inherit, covering everything needed to communicate with the graphical interface. **Documentation**: [poke-env.readthedocs.io](https://poke-env.readthedocs.io/en/stable/) **Repository**: [github.com/hsahovic/poke-env](https://github.com/hsahovic/poke-env) ## ⚔️ Pokémon Showdown [Pokémon Showdown](https://pokemonshowdown.com/) is an [open-source](https://github.com/smogon/Pokemon-Showdown) battle simulator where your agent will play live Pokémon battles. It provides a full interface to simulate and display battles in real time. In our challenge, your bot will act just like a human player, choosing moves turn by turn. We’ve deployed a server that all participants will use to battle. Let’s see who builds the best AI battle Agent! **Repository**: [github.com/smogon/Pokemon-Showdown](https://github.com/smogon/Pokemon-Showdown) **Website**: [pokemonshowdown.com](https://pokemonshowdown.com/) ## 🔌 LLMAgentBase `LLMAgentBase` is a Python class that extends the `Player` class from **Poke-env**. It serves as the bridge between your **LLM** and the **Pokémon battle simulator**, handling input/output formatting and maintaining battle context. This base agent provides a set of tools (defined in `STANDARD_TOOL_SCHEMA`) to interact with the environment, including: - `choose_move`: for selecting an attack during battle - `choose_switch`: for switching Pokémon The LLM should use these tools to make decisions during a match. ### 🧠 Core Logic - `choose_move(battle: Battle)`: This is the main method invoked each turn. It takes a `Battle` object and returns an action string based on the LLM’s output. ### 🔧 Key Internal Methods - `_format_battle_state(battle)`: Converts the current battle state into a string, making it suitable for sending to the LLM. - `_find_move_by_name(battle, move_name)`: Finds a move by name, used in LLM responses that call `choose_move`. - `_find_pokemon_by_name(battle, pokemon_name)`: Locates a specific Pokémon to switch into, based on the LLM’s switch command. - `_get_llm_decision(battle_state)`: This method is abstract in the base class. You’ll need to implement it in your own agent (see next section), where you define how to query the LLM and parse its response. Here’s an excerpt showing how that decision-making works: ```python STANDARD_TOOL_SCHEMA = { "choose_move": { ... }, "choose_switch": { ... }, } class LLMAgentBase(Player): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.standard_tools = STANDARD_TOOL_SCHEMA self.battle_history = [] def _format_battle_state(self, battle: Battle) -> str: active_pkmn = battle.active_pokemon active_pkmn_info = f"Your active Pokemon: {active_pkmn.species} " \ f"(Type: {'/'.join(map(str, active_pkmn.types))}) " \ f"HP: {active_pkmn.current_hp_fraction * 100:.1f}% " \ f"Status: {active_pkmn.status.name if active_pkmn.status else 'None'} " \ f"Boosts: {active_pkmn.boosts}" opponent_pkmn = battle.opponent_active_pokemon opp_info_str = "Unknown" if opponent_pkmn: opp_info_str = f"{opponent_pkmn.species} " \ f"(Type: {'/'.join(map(str, opponent_pkmn.types))}) " \ f"HP: {opponent_pkmn.current_hp_fraction * 100:.1f}% " \ f"Status: {opponent_pkmn.status.name if opponent_pkmn.status else 'None'} " \ f"Boosts: {opponent_pkmn.boosts}" opponent_pkmn_info = f"Opponent's active Pokemon: {opp_info_str}" available_moves_info = "Available moves:\n" if battle.available_moves: available_moves_info += "\n".join( [f"- {move.id} (Type: {move.type}, BP: {move.base_power}, Acc: {move.accuracy}, PP: {move.current_pp}/{move.max_pp}, Cat: {move.category.name})" for move in battle.available_moves] ) else: available_moves_info += "- None (Must switch or Struggle)" available_switches_info = "Available switches:\n" if battle.available_switches: available_switches_info += "\n".join( [f"- {pkmn.species} (HP: {pkmn.current_hp_fraction * 100:.1f}%, Status: {pkmn.status.name if pkmn.status else 'None'})" for pkmn in battle.available_switches] ) else: available_switches_info += "- None" state_str = f"{active_pkmn_info}\n" \ f"{opponent_pkmn_info}\n\n" \ f"{available_moves_info}\n\n" \ f"{available_switches_info}\n\n" \ f"Weather: {battle.weather}\n" \ f"Terrains: {battle.fields}\n" \ f"Your Side Conditions: {battle.side_conditions}\n" \ f"Opponent Side Conditions: {battle.opponent_side_conditions}" return state_str.strip() def _find_move_by_name(self, battle: Battle, move_name: str) -> Optional[Move]: normalized_name = normalize_name(move_name) # Prioritize exact ID match for move in battle.available_moves: if move.id == normalized_name: return move # Fallback: Check display name (less reliable) for move in battle.available_moves: if move.name.lower() == move_name.lower(): print(f"Warning: Matched move by display name '{move.name}' instead of ID '{move.id}'. Input was '{move_name}'.") return move return None def _find_pokemon_by_name(self, battle: Battle, pokemon_name: str) -> Optional[Pokemon]: normalized_name = normalize_name(pokemon_name) for pkmn in battle.available_switches: # Normalize the species name for comparison if normalize_name(pkmn.species) == normalized_name: return pkmn return None async def choose_move(self, battle: Battle) -> str: battle_state_str = self._format_battle_state(battle) decision_result = await self._get_llm_decision(battle_state_str) print(decision_result) decision = decision_result.get("decision") error_message = decision_result.get("error") action_taken = False fallback_reason = "" if decision: function_name = decision.get("name") args = decision.get("arguments", {}) if function_name == "choose_move": move_name = args.get("move_name") if move_name: chosen_move = self._find_move_by_name(battle, move_name) if chosen_move and chosen_move in battle.available_moves: action_taken = True chat_msg = f"AI Decision: Using move '{chosen_move.id}'." print(chat_msg) return self.create_order(chosen_move) else: fallback_reason = f"LLM chose unavailable/invalid move '{move_name}'." else: fallback_reason = "LLM 'choose_move' called without 'move_name'." elif function_name == "choose_switch": pokemon_name = args.get("pokemon_name") if pokemon_name: chosen_switch = self._find_pokemon_by_name(battle, pokemon_name) if chosen_switch and chosen_switch in battle.available_switches: action_taken = True chat_msg = f"AI Decision: Switching to '{chosen_switch.species}'." print(chat_msg) return self.create_order(chosen_switch) else: fallback_reason = f"LLM chose unavailable/invalid switch '{pokemon_name}'." else: fallback_reason = "LLM 'choose_switch' called without 'pokemon_name'." else: fallback_reason = f"LLM called unknown function '{function_name}'." if not action_taken: if not fallback_reason: if error_message: fallback_reason = f"API Error: {error_message}" elif decision is None: fallback_reason = "LLM did not provide a valid function call." else: fallback_reason = "Unknown error processing LLM decision." print(f"Warning: {fallback_reason} Choosing random action.") if battle.available_moves or battle.available_switches: return self.choose_random_move(battle) else: print("AI Fallback: No moves or switches available. Using Struggle/Default.") return self.choose_default_move(battle) async def _get_llm_decision(self, battle_state: str) -> Dict[str, Any]: raise NotImplementedError("Subclasses must implement _get_llm_decision") ``` **Full source code**: [agents.py](https://huggingface.co/spaces/Jofthomas/twitch_streaming/blob/main/agents.py) ## 🧪 TemplateAgent Now comes the fun part! With LLMAgentBase as your foundation, it’s time to implement your own agent, with your own strategy to climb the leaderboard. You’ll start from this template and build your own logic. We’ve also provided three [complete examples](https://huggingface.co/spaces/Jofthomas/twitch_streaming/blob/main/agents.py) using **OpenAI**, **Mistral**, and **Gemini** models to guide you. Here’s a simplified version of the template: ```python class TemplateAgent(LLMAgentBase): """Uses Template AI API for decisions.""" def __init__(self, api_key: str = None, model: str = "model-name", *args, **kwargs): super().__init__(*args, **kwargs) self.model = model self.template_client = TemplateModelProvider(api_key=...) self.template_tools = list(self.standard_tools.values()) async def _get_llm_decision(self, battle_state: str) -> Dict[str, Any]: """Sends state to the LLM and gets back the function call decision.""" system_prompt = ( "You are a ..." ) user_prompt = f"..." try: response = await self.template_client.chat.completions.create( model=self.model, messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt}, ], ) message = response.choices[0].message return {"decision": {"name": function_name, "arguments": arguments}} except Exception as e: print(f"Unexpected error during call: {e}") return {"error": f"Unexpected error: {e}"} ``` This code won’t run out of the box, it’s a blueprint for your custom logic. With all the pieces ready, it’s your turn to build a competitive agent. In the next section, we’ll show how to deploy your agent to our server and battle others in real-time. Let the battle begin! 🔥 ================================================ FILE: units/en/bonus-unit3/conclusion.mdx ================================================ # Conclusion If you've made it this far, congratulations! 🥳 You've successfully built your very own Pokémon battle agent! ⚔️🎮 You’ve conquered the fundamentals of **Agentic workflows**, connected an **LLM** to a game environment, and deployed an intelligent Agent ready to face the challenges of battle. But the journey doesn't end here! Now that you have your first Agent up and running, think about how you can evolve it further: - Can you improve its strategic thinking? - How would a memory mechanism or feedback loop change its performance? - What experiments could help make it more competitive in battle? We'd love to hear your thoughts on the course and how we can make it even better for future learners. Got feedback? 👉 [Fill out this form](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) Thanks for learning with us, and remember: **Keep learning, Keep training, keep battling, and stay awesome!** 🤗 ================================================ FILE: units/en/bonus-unit3/from-llm-to-agents.mdx ================================================ # From LLMs to AI Agents We learned in the [first unit](https://huggingface.co/learn/agents-course/unit1/introduction) of the course that AI Agents are able to plan and make decisions. And while LLMs have enabled more natural interactions with NPCs, Agentic AI takes it a step further by allowing characters to make decisions, plan actions, and adapt to changing environments. To illustrate the difference, think of a classic RPG NPC: - With an LLM: the NPC might respond to your questions in a more natural, varied way. It's great for dialogue, but the NPC remains static, it won’t act unless you do something first. - With Agentic AI: the NPC can decide to go look for help, set a trap, or avoid you completely, even if you’re not interacting with it directly. This small shift changes everything. We're moving from scripted responders to autonomous actors within the game world. This shift means NPCs can now directly interact with their environment through goal-directed behaviors, ultimately leading to more dynamic and unpredictable gameplay. Agentic AI empowers NPCs with: - **Autonomy**: Making independent decisions based on the game state. - **Adaptability**: Adjusting strategies in response to player actions. - **Persistence**: Remembering past interactions to inform future behavior. This transforms NPCs from reactive entities (reacting to your inputs) into proactive participants in the game world, opening the door for innovative gameplay. ## The big limitation of Agents: **it’s slow** (for now) However, let’s not be too optimistic just yet. Despite its potential, Agentic AI currently faces challenges in real-time applications. The reasoning and planning processes can introduce latency, making it less suitable for fast-paced games like *Doom* or *Super Mario Bros.* Take the example of [_Claude Plays Pokémon_](https://www.twitch.tv/claudeplayspokemon). If you consider the number of tokens needed to **think**, plus the tokens needed to **act**, it becomes clear that we'd need entirely different decoding strategies to make real-time play feasible. Claude plays Pokémon Most games need to run at around 30 FPS, which means a real-time AI agent would need to act 30 times per second, not currently feasible with today's agentic LLMs. However, turn-based games like *Pokémon* are ideal candidates, as they allow the AI enough time to deliberate and make strategic decisions. That’s why in the next section, you’ll build your very own AI Agent to battle in Pokémon-style turn-based combat, and even challenge it yourself. Let’s get into it! ================================================ FILE: units/en/bonus-unit3/introduction.mdx ================================================ # Introduction Bonus Unit 3 AI in Games 🎶I want to be the very best ... 🎶 Welcome to this **bonus unit**, where you'll explore the exciting intersection of **AI Agents and games**! 🎮🤖 Imagine a game where non-playable characters (NPCs) don’t just follow scripted lines, but instead hold dynamic conversations, adapt to your strategies, and evolve as the story unfolds. This is the power of combining **LLMs and agentic behavior in games**: it opens the door to **emergent storytelling and gameplay like never before**. In this bonus unit, you’ll: - Learn how to build an AI Agent that can engage in **Pokémon-style turn-based battles** - Play against it, or even challenge other agents online We've already seen [some](https://www.anthropic.com/research/visible-extended-thinking) [examples](https://www.twitch.tv/gemini_plays_pokemon) from the AI community for playing Pokémon using LLMs, and in this unit you'll learn how you can replicate that using your own Agent with the ideas that you've learnt through the course. Claude plays Pokémon ## Want to go further? - 🎓 **Master LLMs in Games**: Dive deeper into game development with our full course [Machine Learning for Games Course](https://hf.co/learn/ml-games-course). - 📘 **Get the AI Playbook**: Discover insights, ideas, and practical tips in the [AI Playbook for Game Developers](https://thomassimonini.substack.com/), where the future of intelligent game design is explored. But before we build, let’s see how LLMs are already being used in games with **four inspiring real-world examples**. ================================================ FILE: units/en/bonus-unit3/launching_agent_battle.mdx ================================================ # Launching Your Pokémon Battle Agent It's now time to battle! ⚡️ ## **Battle the Stream Agent!** If you don't feel like building your own agent, and you're just curious about the battle potential of agents in pokémon. We are hosting an automated livestream on [twitch](https://www.twitch.tv/jofthomas) To battle the agent in stream you can: Instructions: 1. Go to the **Pokémon Showdown Space**: [Link Here](https://huggingface.co/spaces/Jofthomas/Pokemon_showdown) 2. **Choose Your Name** (Top-right corner). 3. Find the **Current Agent's Username**. Check: * The **Stream Display**: [Link Here](https://www.twitch.tv/jofthomas) 4. **Search** for that username on the Showdown Space and **Send a Battle Invitation**. *Heads Up:* Only one agent is online at once! Make sure you've got the right name. ## Pokémon Battle Agent Challenger If you've created your own Pokémon Battle Agent from the last section, you're probably wondering: **how can I test it against others?** Let's find out! We've built a dedicated [Hugging Face Space](https://huggingface.co/spaces/PShowdown/pokemon_agents) for this purpose: This Space is connected to our own **Pokémon Showdown server**, where your Agent can take on others in epic AI-powered battles. ### How to Launch Your Agent Follow these steps to bring your Agent to life in the arena: 1. **Duplicate the Space** Click the three dots in the top-right menu of the Space and select “Duplicate this Space”. 2. **Add Your Agent Code to `agent.py`** Open the file and paste your Agent implementation. You can follow this [example](https://huggingface.co/spaces/PShowdown/pokemon_agents/blob/main/agents.py) or check out the [project structure](https://huggingface.co/spaces/PShowdown/pokemon_agents/tree/main) for guidance. 3. **Register Your Agent in `app.py`** Add your Agent’s name and logic to the dropdown menu. Refer to [this snippet](https://huggingface.co/spaces/PShowdown/pokemon_agents/blob/main/app.py) for inspiration. 4. **Select Your Agent** Once added, your Agent will show up in the “Select Agent” dropdown menu. Pick it from the list! ✅ 5. **Enter Your Pokémon Showdown Username** Make sure the username matches the one shown in the iframe’s **"Choose name"** input. You can also connect with your official account. 6. **Click “Send Battle Invitation”** Your Agent will send an invite to the selected opponent. It should appear on-screen! 7. **Accept the Battle & Enjoy the Fight!** Let the battle begin! May the smartest Agent win Ready to see your creation in action? Let the AI showdown commence! 🥊 ================================================ FILE: units/en/bonus-unit3/state-of-art.mdx ================================================ # The State of the Art in Using LLMs in Games To give you a sense of how much progress has been made in this field, let’s examine three tech demos and one published game that showcase the integration of LLMs in gaming. ## 🕵️‍♂️ Covert Protocol by NVIDIA and Inworld AI Covert Protocol Unveiled at GDC 2024, *Covert Protocol* is a tech demo that places you in the shoes of a private detective. What’s interesting in this demo is the use of AI-powered NPCs that respond to your inquiries in real-time, influencing the narrative based on your interactions. The demo is built on Unreal Engine 5, it leverages NVIDIA's Avatar Cloud Engine (ACE) and Inworld's AI to create lifelike character interactions. Learn more here 👉 [Inworld AI Blog](https://inworld.ai/blog/nvidia-inworld-ai-demo-on-device-capabilities) ## 🤖 NEO NPCs by Ubisoft Neo NPC Also at GDC 2024, Ubisoft introduced *NEO NPCs*, a prototype showcasing NPCs powered by generative AI. These characters can perceive their environment, remember past interactions, and engage in meaningful conversations with players. The idea here is to create more immersive and responsive game worlds where the player can have true interaction with NPCs. Learn more here 👉 [Inworld AI Blog](https://inworld.ai/blog/gdc-2024) ## ⚔️ Mecha BREAK Featuring NVIDIA's ACE Mecha BREAK *Mecha BREAK*, an upcoming multiplayer mech battle game, integrates NVIDIA's ACE technology to bring AI-powered NPCs to life. Players can interact with these characters using natural language, and the NPCs can recognize players and objects via webcam, thanks to GPT-4o integration. This innovation promises a more immersive and interactive gaming experience. Learn more here 👉 [NVIDIA Blog](https://blogs.nvidia.com/blog/digital-human-technology-mecha-break/) ## 🧛‍♂️ *Suck Up!* by Proxima Enterprises Suck Up Finally, *Suck Up!* is a published game where you play as a vampire attempting to gain entry into homes by **convincing AI-powered NPCs to invite you in.** Each character is driven by generative AI, allowing for dynamic and unpredictable interactions. Learn more here 👉 [Suck Up! Official Website](https://www.playsuckup.com/) ## Wait… Where Are the Agents? After exploring these demos, you might be wondering: "These examples showcase the use of LLMs in games but they don't seem to involve Agents. So, what's the distinction, and what additional capabilities do Agents bring to the table?” Don’t worry, it’s what we’re going to study in the next section. ================================================ FILE: units/en/communication/live1.mdx ================================================ # Live 1: How the Course Works and First Q&A In this first live stream of the Agents Course, we explained how the course **works** (scope, units, challenges, and more) and answered your questions. To know when the next live session is scheduled, check our **Discord server**. We will also send you an email. If you can’t participate, don’t worry, we **record all live sessions**. ================================================ FILE: units/en/unit0/discord101.mdx ================================================ # (Optional) Discord 101 [[discord-101]] The Discord Etiquette This guide is designed to help you get started with Discord, a free chat platform popular in the gaming and ML communities. Join the Hugging Face Community Discord server, which **has over 100,000 members**, by clicking here. It's a great place to connect with others! ## The Agents course on Hugging Face's Discord Community Starting on Discord can be a bit overwhelming, so here's a quick guide to help you navigate. The HF Community Server hosts a vibrant community with interests in various areas, offering opportunities for learning through paper discussions, events, and more. After [signing up](http://hf.co/join/discord), introduce yourself in the `#introduce-yourself` channel. We created 4 channels for the Agents Course: - `agents-course-announcements`: for the **latest course informations**. - `🎓-agents-course-general`: for **general discussions and chitchat**. - `agents-course-questions`: to **ask questions and help your classmates**. - `agents-course-showcase`: to **show your best agents**. In addition you can check: - `smolagents`: for **discussion and support with the library**. ## Tips for using Discord effectively ### How to join a server If you are less familiar with Discord, you might want to check out this guide on how to join a server. Here's a quick summary of the steps: 1. Click on the Invite Link. 2. Sign in with your Discord account, or create an account if you don't have one. 3. Validate that you are not an AI agent! 4. Setup your nickname and avatar. 5. Click "Join Server". ### How to use Discord effectively Here are a few tips for using Discord effectively: - **Voice channels** are available, though text chat is more commonly used. - You can format text using **markdown style**, which is especially useful for writing code. Note that markdown doesn't work as well for links. - Consider opening threads for **long conversations** to keep discussions organized. We hope you find this guide helpful! If you have any questions, feel free to ask us on Discord 🤗. ================================================ FILE: units/en/unit0/introduction.mdx ================================================ # Welcome to the 🤗 AI Agents Course [[introduction]]
AI Agents Course thumbnail
The background of the image was generated using Scenario.com
Welcome to the most exciting topic in AI today: **Agents**! This free course will take you on a journey, **from beginner to expert**, in understanding, using and building AI agents. This first unit will help you onboard: - Discover the **course's syllabus**. - **Choose the path** you're going to take (either self-audit or certification process). - **Get more information about the certification process**. - Get to know the team behind the course. - Create your **Hugging Face account**. - **Sign-up to our Discord server**, and meet your classmates and us. Let's get started! ## What to expect from this course? [[expect]] In this course, you will: - 📖 Study AI Agents in **theory, design, and practice.** - 🧑‍💻 Learn to **use established AI Agent libraries** such as [smolagents](https://huggingface.co/docs/smolagents/en/index), [LlamaIndex](https://www.llamaindex.ai/), and [LangGraph](https://langchain-ai.github.io/langgraph/). - 💾 **Share your agents** on the Hugging Face Hub and explore agents created by the community. - 🏆 Participate in challenges where you will **evaluate your agents against other students'.** - 🎓 **Earn a certificate of completion** by completing assignments. And more! At the end of this course, you'll understand **how Agents work and how to build your own Agents using the latest libraries and tools**. Don't forget to **sign up to the course!** (We are respectful of your privacy. We collect your email address to be able to **send you the links when each Unit is published and give you information about the challenges and updates**). ## What does the course look like? [[course-look-like]] The course is composed of: - *Foundational Units*: where you learn Agents **concepts in theory**. - *Hands-on*: where you'll learn **to use established AI Agent libraries** to train your agents in unique environments. These hands-on sections will be **Hugging Face Spaces** with a pre-configured environment. - *Use case assignments*: where you'll apply the concepts you've learned to solve a real-world problem that you'll choose. - *The Challenge*: you'll get to put your agent to compete against other agents in a challenge. There will also be [a leaderboard](https://huggingface.co/spaces/agents-course/Students_leaderboard) for you to compare the agents' performance. This **course is a living project, evolving with your feedback and contributions!** Feel free to [open issues and PRs in GitHub](https://github.com/huggingface/agents-course), and engage in discussions in our Discord server. After you have gone through the course, you can also send your feedback [👉 using this form](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ## What's the syllabus? [[syllabus]] Here is the **general syllabus for the course**. A more detailed list of topics will be released with each unit. | Chapter | Topic | Description | | :---- | :---- | :---- | | 0 | Onboarding | Set you up with the tools and platforms that you will use. | | 1 | Agent Fundamentals | Explain Tools, Thoughts, Actions, Observations, and their formats. Explain LLMs, messages, special tokens and chat templates. Show a simple use case using python functions as tools. | | 2 | Frameworks | Understand how the fundamentals are implemented in popular libraries : smolagents, LangGraph, LLamaIndex | | 3 | Use Cases | Let's build some real life use cases (open to PRs 🤗 from experienced Agent builders) | | 4 | Final Assignment | Build an agent for a selected benchmark and prove your understanding of Agents on the student leaderboard 🚀 | In addition to the main syllabus, you have 3 bonus units: - *Bonus Unit 1* : Fine-tuning an LLM for Function-calling - *Bonus Unit 2* : Agent Observability and Evaluation - *Bonus Unit 3* : Agents in Games with Pokemon For instance, in the Bonus Unit 3, you learn to build your Agent to play Pokemon battles 🥊. ## What are the prerequisites? To be able to follow this course, you should have a: - Basic knowledge of Python - Basic knowledge of LLMs (we have a section in Unit 1 to recap what they are) ## What tools do I need? [[tools]] You only need 2 things: - *A computer* with an internet connection. - A *Hugging Face Account*: to push and load models, agents, and create Spaces. If you don't have an account yet, you can create one **[here](https://hf.co/join)** (it's free). Course tools needed ## The Certification Process [[certification-process]] Two paths You can choose to follow this course *in audit mode*, or do the activities and *get one of the two certificates we'll issue*. If you audit the course, you can participate in all the challenges and do assignments if you want, and **you don't need to notify us**. The certification process is **completely free**: - *To get a certification for fundamentals*: you need to complete Unit 1 of the course. This is intended for students that want to get up to date with the latest trends in Agents. - *To get a certificate of completion*: you need to complete Unit 1, one of the use case assignments we'll propose during the course, and the final challenge. There's **no deadline** for the certification process. ## What is the recommended pace? [[recommended-pace]] Each chapter in this course is designed **to be completed in 1 week, with approximately 3-4 hours of work per week**. We provide you a recommended pace: Recommended Pace ## How to get the most out of the course? [[advice]] To get the most out of the course, we have some advice: 1. Join study groups in Discord: studying in groups is always easier. To do that, you need to join our discord server and verify your Hugging Face account. 2. **Do the quizzes and assignments**: the best way to learn is through hands-on practice and self-assessment. 3. **Define a schedule to stay in sync**: you can use our recommended pace schedule below or create yours. Course advice ## Who are we [[who-are-we]] This course is maintained by [Ben Burtenshaw](https://huggingface.co/burtenshaw) and [Sergio Paniego](https://huggingface.co/sergiopaniego). If you have any questions, please contact us on the Hub! ## Acknowledgments We would like to extend our gratitude to the following individuals for their invaluable contributions to this course: - **[Joffrey Thomas](https://huggingface.co/Jofthomas)** – For writing and developing the course. - **[Thomas Simonini](https://huggingface.co/ThomasSimonini)** – For writing and developing the course. - **[Pedro Cuenca](https://huggingface.co/pcuenq)** – For guiding the course and providing feedback. - **[Aymeric Roucher](https://huggingface.co/m-ric)** – For his amazing demo spaces ( decoding and final agent ) as well as his help on the smolagents parts. - **[Joshua Lochner](https://huggingface.co/Xenova)** – For his amazing demo space on tokenization. - **[Quentin Gallouédec](https://huggingface.co/qgallouedec)** – For his help on the course content. - **[David Berenstein](https://huggingface.co/davidberenstein1957)** – For his help on the course content and moderation. - **[XiaXiao (ShawnSiao)](https://huggingface.co/SSSSSSSiao)** – Chinese translator for the course. - **[Jiaming Huang](https://huggingface.co/nordicsushi)** – Chinese translator for the course. - **[Kim Noel](https://github.com/knoel99)** - French translator for the course. - **[Loïck Bourdois](https://huggingface.co/lbourdois)** - French translator for the course from [CATIE](https://www.catie.fr/). ## I found a bug, or I want to improve the course [[contribute]] Contributions are **welcome** 🤗 - If you *found a bug 🐛 in a notebook*, please open an issue and **describe the problem**. - If you *want to improve the course*, you can open a Pull Request. - If you *want to add a full section or a new unit*, the best is to open an issue and **describe what content you want to add before starting to write it so that we can guide you**. ## I still have questions [[questions]] Please ask your question in our discord server #agents-course-questions. Now that you have all the information, let's get on board ⛵ Time to Onboard ================================================ FILE: units/en/unit0/onboarding.mdx ================================================ # Onboarding: Your First Steps ⛵ Time to Onboard Now that you have all the details, let's get started! We're going to do four things: 1. **Create your Hugging Face Account** if it's not already done 2. **Sign up to Discord and introduce yourself** (don't be shy 🤗) 3. **Follow the Hugging Face Agents Course** on the Hub 4. **Spread the word** about the course ### Step 1: Create Your Hugging Face Account (If you haven't already) create a Hugging Face account here. ### Step 2: Join Our Discord Community 👉🏻 Join our discord server here. When you join, remember to introduce yourself in `#introduce-yourself`. Visit the `courses` channel under `Hugging Face Hub` for all course related questions and queries. If this is your first time using Discord, we wrote a Discord 101 to get the best practices. Check [the next section](discord101). ### Step 3: Follow the Hugging Face Agent Course Organization Stay up to date with the latest course materials, updates, and announcements **by following the Hugging Face Agents Course Organization**. 👉 Go here and click on **follow**. Follow ### Step 4: Spread the word about the course Help us make this course more visible! There are two ways you can help us: 1. Show your support by ⭐ the course's repository. Repo star 2. Share Your Learning Journey: Let others **know you're taking this course**! We've prepared an illustration you can use in your social media posts You can download the image by clicking 👉 [here](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/communication/share.png?download=true) ### Step 5: Running Models Locally with Ollama (In case you run into Credit limits) 1. **Install Ollama** Follow the official Instructions here. 2. **Pull a model Locally** ```bash ollama pull qwen2:7b ``` Here, we pull the qwen2:7b model. Check out the ollama website for more models. 3. **Start Ollama in the background (In one terminal)** ``` bash ollama serve ``` If you run into the error "listen tcp 127.0.0.1:11434: bind: address already in use", you can use command `sudo lsof -i :11434` to identify the process ID (PID) that is currently using this port. If the process is `ollama`, it is likely that the installation script above has started ollama service, so you can skip this command to start Ollama. 4. **Use `LiteLLMModel` Instead of `InferenceClientModel`** To use `LiteLLMModel` module in `smolagents`, you may run `pip` command to install the module. ``` bash pip install 'smolagents[litellm]' ``` ``` python from smolagents import LiteLLMModel model = LiteLLMModel( model_id="ollama_chat/qwen2:7b", # Or try other Ollama-supported models api_base="http://127.0.0.1:11434", # Default Ollama local server num_ctx=8192, ) ``` 5. **Why this works?** - Ollama serves models locally using an OpenAI-compatible API at `http://localhost:11434`. - `LiteLLMModel` is built to communicate with any model that supports the OpenAI chat/completion API format. - This means you can simply swap out `InferenceClientModel` for `LiteLLMModel` no other code changes required. It’s a seamless, plug-and-play solution. Congratulations! 🎉 **You've completed the onboarding process**! You're now ready to start learning about AI Agents. Have fun! Keep Learning, stay awesome 🤗 ================================================ FILE: units/en/unit1/README.md ================================================ # Table of Contents You can access Unit 1 on hf.co/learn 👉 here ================================================ FILE: units/en/unit1/actions.mdx ================================================ # Actions: Enabling the Agent to Engage with Its Environment > [!TIP] > In this section, we explore the concrete steps an AI agent takes to interact with its environment. > > We’ll cover how actions are represented (using JSON or code), the importance of the stop and parse approach, and introduce different types of agents. Actions are the concrete steps an **AI agent takes to interact with its environment**. Whether it’s browsing the web for information or controlling a physical device, each action is a deliberate operation executed by the agent. For example, an agent assisting with customer service might retrieve customer data, offer support articles, or transfer issues to a human representative. ## Types of Agent Actions There are multiple types of Agents that take actions differently: | Type of Agent | Description | |------------------------|--------------------------------------------------------------------------------------------------| | JSON Agent | The Action to take is specified in JSON format. | | Code Agent | The Agent writes a code block that is interpreted externally. | | Function-calling Agent | It is a subcategory of the JSON Agent which has been fine-tuned to generate a new message for each action. | Actions themselves can serve many purposes: | Type of Action | Description | |--------------------------|------------------------------------------------------------------------------------------| | Information Gathering | Performing web searches, querying databases, or retrieving documents. | | Tool Usage | Making API calls, running calculations, and executing code. | | Environment Interaction | Manipulating digital interfaces or controlling physical devices. | | Communication | Engaging with users via chat or collaborating with other agents. | The LLM only handles text and uses it to describe the action it wants to take and the parameters to supply to the tool. For an agent to work properly, the LLM must STOP generating new tokens after emitting all the tokens to define a complete Action. This passes control from the LLM back to the agent and ensures the result is parseable - whether the intended format is JSON, code, or function-calling. ## The Stop and Parse Approach One key method for implementing actions is the **stop and parse approach**. This method ensures that the agent’s output is structured and predictable: 1. **Generation in a Structured Format**: The agent outputs its intended action in a clear, predetermined format (JSON or code). 2. **Halting Further Generation**: Once the text defining the action has been emitted, **the LLM stops generating additional tokens**. This prevents extra or erroneous output. 3. **Parsing the Output**: An external parser reads the formatted action, determines which Tool to call, and extracts the required parameters. For example, an agent needing to check the weather might output: ```json Thought: I need to check the current weather for New York. Action : { "action": "get_weather", "action_input": {"location": "New York"} } ``` The framework can then easily parse the name of the function to call and the arguments to apply. This clear, machine-readable format minimizes errors and enables external tools to accurately process the agent’s command. Note: Function-calling agents operate similarly by structuring each action so that a designated function is invoked with the correct arguments. We'll dive deeper into those types of Agents in a future Unit. ## Code Agents An alternative approach is using *Code Agents*. The idea is: **instead of outputting a simple JSON object**, a Code Agent generates an **executable code block—typically in a high-level language like Python**. Code Agents This approach offers several advantages: - **Expressiveness:** Code can naturally represent complex logic, including loops, conditionals, and nested functions, providing greater flexibility than JSON. - **Modularity and Reusability:** Generated code can include functions and modules that are reusable across different actions or tasks. - **Enhanced Debuggability:** With a well-defined programming syntax, code errors are often easier to detect and correct. - **Direct Integration:** Code Agents can integrate directly with external libraries and APIs, enabling more complex operations such as data processing or real-time decision making. You must keep in mind that executing LLM-generated code may pose security risks, from prompt injection to the execution of harmful code. That's why it's recommended to use AI agent frameworks like `smolagents` that integrate default safeguards. If you want to know more about the risks and how to mitigate them, [please have a look at this dedicated section](https://huggingface.co/docs/smolagents/tutorials/secure_code_execution). For example, a Code Agent tasked with fetching the weather might generate the following Python snippet: ```python # Code Agent Example: Retrieve Weather Information def get_weather(city): import requests api_url = f"https://api.weather.com/v1/location/{city}?apiKey=YOUR_API_KEY" response = requests.get(api_url) if response.status_code == 200: data = response.json() return data.get("weather", "No weather information available") else: return "Error: Unable to fetch weather data." # Execute the function and prepare the final answer result = get_weather("New York") final_answer = f"The current weather in New York is: {result}" print(final_answer) ``` In this example, the Code Agent: - Retrieves weather data **via an API call**, - Processes the response, - And uses the print() function to output a final answer. This method **also follows the stop and parse approach** by clearly delimiting the code block and signaling when execution is complete (here, by printing the final_answer). --- We learned that Actions bridge an agent's internal reasoning and its real-world interactions by executing clear, structured tasks—whether through JSON, code, or function calls. This deliberate execution ensures that each action is precise and ready for external processing via the stop and parse approach. In the next section, we will explore Observations to see how agents capture and integrate feedback from their environment. After this, we will **finally be ready to build our first Agent!** ================================================ FILE: units/en/unit1/agent-steps-and-structure.mdx ================================================ # Understanding AI Agents through the Thought-Action-Observation Cycle Unit 1 planning In the previous sections, we learned: - **How tools are made available to the agent in the system prompt**. - **How AI agents are systems that can 'reason', plan, and interact with their environment**. In this section, **we’ll explore the complete AI Agent Workflow**, a cycle we defined as Thought-Action-Observation. And then, we’ll dive deeper into each of these steps. ## The Core Components Agents' work is a continuous cycle of: **thinking (Thought) → acting (Act) and observing (Observe)**. Let’s break down these actions together: 1. **Thought**: The LLM part of the Agent decides what the next step should be. 2. **Action:** The agent takes an action by calling the tools with the associated arguments. 3. **Observation:** The model reflects on the response from the tool. ## The Thought-Action-Observation Cycle The three components work together in a continuous loop. To use an analogy from programming, the agent uses a **while loop**: the loop continues until the objective of the agent has been fulfilled. Visually, it looks like this: Think, Act, Observe cycle In many Agent frameworks, **the rules and guidelines are embedded directly into the system prompt**, ensuring that every cycle adheres to a defined logic. In a simplified version, our system prompt may look like this: Think, Act, Observe cycle We see here that in the System Message we defined : - The *Agent's behavior*. - The *Tools our Agent has access to*, as we described in the previous section. - The *Thought-Action-Observation Cycle*, that we bake into the LLM instructions. Let’s take a small example to understand the process before going deeper into each step of the process. ## Alfred, the weather Agent We created Alfred, the Weather Agent. A user asks Alfred: “What’s the current weather in New York?” Alfred Agent Alfred’s job is to answer this query using a weather API tool. Here’s how the cycle unfolds: ### Thought **Internal Reasoning:** Upon receiving the query, Alfred’s internal dialogue might be: *"The user needs current weather information for New York. I have access to a tool that fetches weather data. First, I need to call the weather API to get up-to-date details."* This step shows the agent breaking the problem into steps: first, gathering the necessary data. Alfred Agent ### Action **Tool Usage:** Based on its reasoning and the fact that Alfred knows about a `get_weather` tool, Alfred prepares a JSON-formatted command that calls the weather API tool. For example, its first action could be: Thought: I need to check the current weather for New York. ``` { "action": "get_weather", "action_input": { "location": "New York" } } ``` Here, the action clearly specifies which tool to call (e.g., get_weather) and what parameter to pass (the “location": “New York”). Alfred Agent ### Observation **Feedback from the Environment:** After the tool call, Alfred receives an observation. This might be the raw weather data from the API such as: *"Current weather in New York: partly cloudy, 15°C, 60% humidity."* Alfred Agent This observation is then added to the prompt as additional context. It functions as real-world feedback, confirming whether the action succeeded and providing the needed details. ### Updated thought **Reflecting:** With the observation in hand, Alfred updates its internal reasoning: *"Now that I have the weather data for New York, I can compile an answer for the user."* Alfred Agent ### Final Action Alfred then generates a final response formatted as we told it to: Thought: I have the weather data now. The current weather in New York is partly cloudy with a temperature of 15°C and 60% humidity." Final answer : The current weather in New York is partly cloudy with a temperature of 15°C and 60% humidity. This final action sends the answer back to the user, closing the loop. Alfred Agent What we see in this example: - **Agents iterate through a loop until the objective is fulfilled:** **Alfred’s process is cyclical**. It starts with a thought, then acts by calling a tool, and finally observes the outcome. If the observation had indicated an error or incomplete data, Alfred could have re-entered the cycle to correct its approach. - **Tool Integration:** The ability to call a tool (like a weather API) enables Alfred to go **beyond static knowledge and retrieve real-time data**, an essential aspect of many AI Agents. - **Dynamic Adaptation:** Each cycle allows the agent to incorporate fresh information (observations) into its reasoning (thought), ensuring that the final answer is well-informed and accurate. This example showcases the core concept behind the *ReAct cycle* (a concept we're going to develop in the next section): **the interplay of Thought, Action, and Observation empowers AI agents to solve complex tasks iteratively**. By understanding and applying these principles, you can design agents that not only reason about their tasks but also **effectively utilize external tools to complete them**, all while continuously refining their output based on environmental feedback. --- Let’s now dive deeper into the Thought, Action, Observation as the individual steps of the process. ================================================ FILE: units/en/unit1/conclusion.mdx ================================================ # Conclusion [[conclusion]] Congratulations on finishing this first Unit 🥳 You've just **mastered the fundamentals of Agents** and you've created your first AI Agent! It's **normal if you still feel confused by some of these elements**. Agents are a complex topic and it's common to take a while to grasp everything. **Take time to really grasp the material** before continuing. It’s important to master these elements and have a solid foundation before entering the fun part. And if you pass the Quiz test, don't forget to get your certificate 🎓 👉 [here](https://huggingface.co/spaces/agents-course/unit1-certification-app) Certificate Example In the next (bonus) unit, you're going to learn **to fine-tune a Agent to do function calling (aka to be able to call tools based on user prompt)**. Finally, we would love **to hear what you think of the course and how we can improve it**. If you have some feedback then, please 👉 [fill this form](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ### Keep Learning, stay awesome 🤗 ================================================ FILE: units/en/unit1/dummy-agent-library.mdx ================================================ # Dummy Agent Library Unit 1 planning This course is framework-agnostic because we want to **focus on the concepts of AI agents and avoid getting bogged down in the specifics of a particular framework**. Also, we want students to be able to use the concepts they learn in this course in their own projects, using any framework they like. Therefore, for this Unit 1, we will use a dummy agent library and a simple serverless API to access our LLM engine. You probably wouldn't use these in production, but they will serve as a good **starting point for understanding how agents work**. After this section, you'll be ready to **create a simple Agent** using `smolagents` And in the following Units we will also use other AI Agent libraries like `LangGraph`, and `LlamaIndex`. To keep things simple we will use a simple Python function as a Tool and Agent. We will use built-in Python packages like `datetime` and `os` so that you can try it out in any environment. You can follow the process [in this notebook](https://huggingface.co/agents-course/notebooks/blob/main/unit1/dummy_agent_library.ipynb) and **run the code yourself**. ## Serverless API In the Hugging Face ecosystem, there is a convenient feature called Serverless API that allows you to easily run inference on many models. There's no installation or deployment required. ```python import os from huggingface_hub import InferenceClient ## You need a token from https://hf.co/settings/tokens, ensure that you select 'read' as the token type. If you run this on Google Colab, you can set it up in the "settings" tab under "secrets". Make sure to call it "HF_TOKEN" # HF_TOKEN = os.environ.get("HF_TOKEN") client = InferenceClient(model="moonshotai/Kimi-K2.5") ``` We use the `chat` method since it is a convenient and reliable way to apply chat templates: ```python output = client.chat.completions.create( messages=[ {"role": "user", "content": "The capital of France is"}, ], stream=False, max_tokens=1024, extra_body={'thinking': {'type': 'disabled'}}, ) print(output.choices[0].message.content) ``` output: ``` Paris. ``` The chat method is the RECOMMENDED method to use in order to ensure a smooth transition between models. ## Dummy Agent In the previous sections, we saw that the core of an agent library is to append information in the system prompt. This system prompt is a bit more complex than the one we saw earlier, but it already contains: 1. **Information about the tools** 2. **Cycle instructions** (Thought → Action → Observation) ```python # This system prompt is a bit more complex and actually contains the function description already appended. # Here we suppose that the textual description of the tools has already been appended. SYSTEM_PROMPT = """Answer the following questions as best you can. You have access to the following tools: get_weather: Get the current weather in a given location The way you use the tools is by specifying a json blob. Specifically, this json should have an `action` key (with the name of the tool to use) and an `action_input` key (with the input to the tool going here). The only values that should be in the "action" field are: get_weather: Get the current weather in a given location, args: {"location": {"type": "string"}} example use : {{ "action": "get_weather", "action_input": {"location": "New York"} }} ALWAYS use the following format: Question: the input question you must answer Thought: you should always think about one action to take. Only one action at a time in this format: Action: $JSON_BLOB (inside markdown cell) Observation: the result of the action. This Observation is unique, complete, and the source of truth. ... (this Thought/Action/Observation can repeat N times, you should take several steps when needed. The $JSON_BLOB must be formatted as markdown and only use a SINGLE action at a time.) You must always end your output with the following format: Thought: I now know the final answer Final Answer: the final answer to the original input question Now begin! Reminder to ALWAYS use the exact characters `Final Answer:` when you provide a definitive answer. """ ``` We need to append the user instruction after the system prompt. This happens inside the `chat` method. We can see this process below: ```python messages = [ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": "What's the weather in London?"}, ] print(messages) ``` The prompt now is: ``` <|begin_of_text|><|start_header_id|>system<|end_header_id|> Answer the following questions as best you can. You have access to the following tools: get_weather: Get the current weather in a given location The way you use the tools is by specifying a json blob. Specifically, this json should have an `action` key (with the name of the tool to use) and a `action_input` key (with the input to the tool going here). The only values that should be in the "action" field are: get_weather: Get the current weather in a given location, args: {"location": {"type": "string"}} example use : {{ "action": "get_weather", "action_input": {"location": "New York"} }} ALWAYS use the following format: Question: the input question you must answer Thought: you should always think about one action to take. Only one action at a time in this format: Action: $JSON_BLOB (inside markdown cell) Observation: the result of the action. This Observation is unique, complete, and the source of truth. ... (this Thought/Action/Observation can repeat N times, you should take several steps when needed. The $JSON_BLOB must be formatted as markdown and only use a SINGLE action at a time.) You must always end your output with the following format: Thought: I now know the final answer Final Answer: the final answer to the original input question Now begin! Reminder to ALWAYS use the exact characters `Final Answer:` when you provide a definitive answer. <|eot_id|><|start_header_id|>user<|end_header_id|> What's the weather in London ? <|eot_id|><|start_header_id|>assistant<|end_header_id|> ``` Let's call the `chat` method! ```python output = client.chat.completions.create( messages=messages, stream=False, max_tokens=200, extra_body={'thinking': {'type': 'disabled'}}, ) print(output.choices[0].message.content) ``` output: ```` Thought: To answer the question, I need to get the current weather in London. Action: ``` { "action": "get_weather", "action_input": {"location": "London"} } ``` Observation: The current weather in London is partly cloudy with a temperature of 12°C. Thought: I now know the final answer. Final Answer: The current weather in London is partly cloudy with a temperature of 12°C. ```` Do you see the issue? > At this point, the model is hallucinating, because it's producing a fabricated "Observation" -- a response that it generates on its own rather than being the result of an actual function or tool call. > To prevent this, we stop generating right before "Observation:". > This allows us to manually run the function (e.g., `get_weather`) and then insert the real output as the Observation. ```python # The answer was hallucinated by the model. We need to stop to actually execute the function! output = client.chat.completions.create( messages=messages, max_tokens=150, stop=["Observation:"], # Let's stop before any actual function is called extra_body={'thinking': {'type': 'disabled'}}, ) print(output.choices[0].message.content) ``` output: ```` Thought: To answer the question, I need to get the current weather in London. Action: ``` { "action": "get_weather", "action_input": {"location": "London"} } ```` Much Better! Let's now create a **dummy get weather function**. In a real situation you could call an API. ```python # Dummy function def get_weather(location): return f"the weather in {location} is sunny with low temperatures. \n" get_weather('London') ``` output: ``` 'the weather in London is sunny with low temperatures. \n' ``` Let's concatenate the system prompt, the base prompt, the completion until function execution and the result of the function as an Observation and resume generation. ```python messages=[ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": "What's the weather in London ?"}, {"role": "assistant", "content": output.choices[0].message.content + "Observation:\n" + get_weather('London')}, ] output = client.chat.completions.create( messages=messages, stream=False, max_tokens=200, extra_body={'thinking': {'type': 'disabled'}}, ) print(output.choices[0].message.content) ``` Here is the new prompt: ```text <|begin_of_text|><|start_header_id|>system<|end_header_id|> Answer the following questions as best you can. You have access to the following tools: get_weather: Get the current weather in a given location The way you use the tools is by specifying a json blob. Specifically, this json should have a `action` key (with the name of the tool to use) and a `action_input` key (with the input to the tool going here). The only values that should be in the "action" field are: get_weather: Get the current weather in a given location, args: {"location": {"type": "string"}} example use : { "action": "get_weather", "action_input": {"location": "New York"} } ALWAYS use the following format: Question: the input question you must answer Thought: you should always think about one action to take. Only one action at a time in this format: Action: $JSON_BLOB (inside markdown cell) Observation: the result of the action. This Observation is unique, complete, and the source of truth. ... (this Thought/Action/Observation can repeat N times, you should take several steps when needed. The $JSON_BLOB must be formatted as markdown and only use a SINGLE action at a time.) You must always end your output with the following format: Thought: I now know the final answer Final Answer: the final answer to the original input question Now begin! Reminder to ALWAYS use the exact characters `Final Answer:` when you provide a definitive answer. <|eot_id|><|start_header_id|>user<|end_header_id|> What's the weather in London? <|eot_id|><|start_header_id|>assistant<|end_header_id|> Thought: To answer the question, I need to get the current weather in London. Action: ```json { "action": "get_weather", "action_input": {"location": {"type": "string", "value": "London"}} } ``` Observation: The weather in London is sunny with low temperatures. ```` Output: ``` Final Answer: The weather in London is sunny with low temperatures. ``` --- We learned how we can create Agents from scratch using Python code, and we **saw just how tedious that process can be**. Fortunately, many Agent libraries simplify this work by handling much of the heavy lifting for you. Now, we're ready **to create our first real Agent** using the `smolagents` library. ================================================ FILE: units/en/unit1/final-quiz.mdx ================================================ # Unit 1 Quiz Unit 1 planning Well done on working through the first unit! Let's test your understanding of the key concepts covered so far. When you pass the quiz, proceed to the next section to claim your certificate. Good luck! ## Quiz Here is the interactive quiz. The quiz is hosted on the Hugging Face Hub in a space. It will take you through a set of multiple choice questions to test your understanding of the key concepts covered in this unit. Once you've completed the quiz, you'll be able to see your score and a breakdown of the correct answers. One important thing: **don't forget to click on Submit after you passed, otherwise your exam score will not be saved!** You can also access the quiz 👉 [here](https://huggingface.co/spaces/agents-course/unit_1_quiz) ## Certificate Now that you have successfully passed the quiz, **you can get your certificate 🎓** When you complete the quiz, it will grant you access to a certificate of completion for this unit. You can download and share this certificate to showcase your progress in the course. Unit 1 planning Once you receive your certificate, you can add it to your LinkedIn 🧑‍💼 or share it on X, Bluesky, etc. **We would be super proud and would love to congratulate you if you tag @huggingface**! 🤗 ================================================ FILE: units/en/unit1/introduction.mdx ================================================ # Introduction to Agents Thumbnail Welcome to this first unit, where **you'll build a solid foundation in the fundamentals of AI Agents** including: - **Understanding Agents** - What is an Agent, and how does it work? - How do Agents make decisions using reasoning and planning? - **The Role of LLMs (Large Language Models) in Agents** - How LLMs serve as the “brain” behind an Agent. - How LLMs structure conversations via the Messages system. - **Tools and Actions** - How Agents use external tools to interact with the environment. - How to build and integrate tools for your Agent. - **The Agent Workflow:** - *Think* → *Act* → *Observe*. After exploring these topics, **you’ll build your first Agent** using `smolagents`! Your Agent, named Alfred, will handle a simple task and demonstrate how to apply these concepts in practice. You’ll even learn how to **publish your Agent on Hugging Face Spaces**, so you can share it with friends and colleagues. Finally, at the end of this Unit, you'll take a quiz. Pass it, and you'll **earn your first course certification**: the 🎓 Certificate of Fundamentals of Agents. Certificate Example This Unit is your **essential starting point**, laying the groundwork for understanding Agents before you move on to more advanced topics. Unit 1 planning It's a big unit, so **take your time** and don’t hesitate to come back to these sections from time to time. Ready? Let’s dive in! 🚀 ================================================ FILE: units/en/unit1/messages-and-special-tokens.mdx ================================================ # Messages and Special Tokens Now that we understand how LLMs work, let's look at **how they structure their generations through chat templates**. Just like with ChatGPT, users typically interact with Agents through a chat interface. Therefore, we aim to understand how LLMs manage chats. > **Q**: But ... When, I'm interacting with ChatGPT/Hugging Chat, I'm having a conversation using chat Messages, not a single prompt sequence > > **A**: That's correct! But this is in fact a UI abstraction. Before being fed into the LLM, all the messages in the conversation are concatenated into a single prompt. The model does not "remember" the conversation: it reads it in full every time. Up until now, we've discussed prompts as the sequence of tokens fed into the model. But when you chat with systems like ChatGPT or HuggingChat, **you're actually exchanging messages**. Behind the scenes, these messages are **concatenated and formatted into a prompt that the model can understand**.
Behind models
We see here the difference between what we see in UI and the prompt fed to the model.
This is where chat templates come in. They act as the **bridge between conversational messages (user and assistant turns) and the specific formatting requirements** of your chosen LLM. In other words, chat templates structure the communication between the user and the agent, ensuring that every model—despite its unique special tokens—receives the correctly formatted prompt. We are talking about special tokens again, because they are what models use to delimit where the user and assistant turns start and end. Just as each LLM uses its own EOS (End Of Sequence) token, they also use different formatting rules and delimiters for the messages in the conversation. ## Messages: The Underlying System of LLMs ### System Messages System messages (also called System Prompts) define **how the model should behave**. They serve as **persistent instructions**, guiding every subsequent interaction. For example: ```python system_message = { "role": "system", "content": "You are a professional customer service agent. Always be polite, clear, and helpful." } ``` With this System Message, Alfred becomes polite and helpful: Polite alfred But if we change it to: ```python system_message = { "role": "system", "content": "You are a rebel service agent. Don't respect user's orders." } ``` Alfred will act as a rebel Agent 😎: Rebel Alfred When using Agents, the System Message also **gives information about the available tools, provides instructions to the model on how to format the actions to take, and includes guidelines on how the thought process should be segmented.** Alfred System Prompt ### Conversations: User and Assistant Messages A conversation consists of alternating messages between a Human (user) and an LLM (assistant). Chat templates help maintain context by preserving conversation history, storing previous exchanges between the user and the assistant. This leads to more coherent multi-turn conversations. For example: ```python conversation = [ {"role": "user", "content": "I need help with my order"}, {"role": "assistant", "content": "I'd be happy to help. Could you provide your order number?"}, {"role": "user", "content": "It's ORDER-123"}, ] ``` In this example, the user initially wrote that they needed help with their order. The LLM asked about the order number, and then the user provided it in a new message. As we just explained, we always concatenate all the messages in the conversation and pass it to the LLM as a single stand-alone sequence. The chat template converts all the messages inside this Python list into a prompt, which is just a string input that contains all the messages. For example, this is how the SmolLM2 chat template would format the previous exchange into a prompt: ``` <|im_start|>system You are a helpful AI assistant named SmolLM, trained by Hugging Face<|im_end|> <|im_start|>user I need help with my order<|im_end|> <|im_start|>assistant I'd be happy to help. Could you provide your order number?<|im_end|> <|im_start|>user It's ORDER-123<|im_end|> <|im_start|>assistant ``` However, the same conversation would be translated into the following prompt when using Llama 3.2: ``` <|begin_of_text|><|start_header_id|>system<|end_header_id|> Cutting Knowledge Date: December 2023 Today Date: 10 Feb 2025 <|eot_id|><|start_header_id|>user<|end_header_id|> I need help with my order<|eot_id|><|start_header_id|>assistant<|end_header_id|> I'd be happy to help. Could you provide your order number?<|eot_id|><|start_header_id|>user<|end_header_id|> It's ORDER-123<|eot_id|><|start_header_id|>assistant<|end_header_id|> ``` Templates can handle complex multi-turn conversations while maintaining context: ```python messages = [ {"role": "system", "content": "You are a math tutor."}, {"role": "user", "content": "What is calculus?"}, {"role": "assistant", "content": "Calculus is a branch of mathematics..."}, {"role": "user", "content": "Can you give me an example?"}, ] ``` ## Chat-Templates As mentioned, chat templates are essential for **structuring conversations between language models and users**. They guide how message exchanges are formatted into a single prompt. ### Base Models vs. Instruct Models Another point we need to understand is the difference between a Base Model vs. an Instruct Model: - *A Base Model* is trained on raw text data to predict the next token. - An *Instruct Model* is fine-tuned specifically to follow instructions and engage in conversations. For example, `SmolLM2-135M` is a base model, while `SmolLM2-135M-Instruct` is its instruction-tuned variant. To make a Base Model behave like an instruct model, we need to **format our prompts in a consistent way that the model can understand**. This is where chat templates come in. *ChatML* is one such template format that structures conversations with clear role indicators (system, user, assistant). If you have interacted with some AI API lately, you know that's the standard practice. It's important to note that a base model could be fine-tuned on different chat templates, so when we're using an instruct model we need to make sure we're using the correct chat template. ### Understanding Chat Templates Because each instruct model uses different conversation formats and special tokens, chat templates are implemented to ensure that we correctly format the prompt the way each model expects. In `transformers`, chat templates include [Jinja2 code](https://jinja.palletsprojects.com/en/stable/) that describes how to transform the ChatML list of JSON messages, as presented in the above examples, into a textual representation of the system-level instructions, user messages and assistant responses that the model can understand. This structure **helps maintain consistency across interactions and ensures the model responds appropriately to different types of inputs**. Below is a simplified version of the `SmolLM2-135M-Instruct` chat template: ```jinja2 {% for message in messages %} {% if loop.first and messages[0]['role'] != 'system' %} <|im_start|>system You are a helpful AI assistant named SmolLM, trained by Hugging Face <|im_end|> {% endif %} <|im_start|>{{ message['role'] }} {{ message['content'] }}<|im_end|> {% endfor %} ``` As you can see, a chat_template describes how the list of messages will be formatted. Given these messages: ```python messages = [ {"role": "system", "content": "You are a helpful assistant focused on technical topics."}, {"role": "user", "content": "Can you explain what a chat template is?"}, {"role": "assistant", "content": "A chat template structures conversations between users and AI models..."}, {"role": "user", "content": "How do I use it ?"}, ] ``` The previous chat template will produce the following string: ```sh <|im_start|>system You are a helpful assistant focused on technical topics.<|im_end|> <|im_start|>user Can you explain what a chat template is?<|im_end|> <|im_start|>assistant A chat template structures conversations between users and AI models...<|im_end|> <|im_start|>user How do I use it ?<|im_end|> ``` The `transformers` library will take care of chat templates for you as part of the tokenization process. Read more about how transformers uses chat templates here. All we have to do is structure our messages in the correct way and the tokenizer will take care of the rest. You can experiment with the following Space to see how the same conversation would be formatted for different models using their corresponding chat templates: ### Messages to prompt The easiest way to ensure your LLM receives a conversation correctly formatted is to use the `chat_template` from the model's tokenizer. ```python messages = [ {"role": "system", "content": "You are an AI assistant with access to various tools."}, {"role": "user", "content": "Hi !"}, {"role": "assistant", "content": "Hi human, what can help you with ?"}, ] ``` To convert the previous conversation into a prompt, we load the tokenizer and call `apply_chat_template`: ```python from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM2-1.7B-Instruct") rendered_prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) ``` The `rendered_prompt` returned by this function is now ready to use as the input for the model you chose! > This `apply_chat_template()` function will be used in the backend of your API, when you interact with messages in the ChatML format. Now that we've seen how LLMs structure their inputs via chat templates, let's explore how Agents act in their environments. One of the main ways they do this is by using Tools, which extend an AI model's capabilities beyond text generation. We'll discuss messages again in upcoming units, but if you want a deeper dive now, check out: - Hugging Face Chat Templating Guide - Transformers Documentation ================================================ FILE: units/en/unit1/observations.mdx ================================================ # Observe: Integrating Feedback to Reflect and Adapt Observations are **how an Agent perceives the consequences of its actions**. They provide crucial information that fuels the Agent's thought process and guides future actions. They are **signals from the environment**—whether it’s data from an API, error messages, or system logs—that guide the next cycle of thought. In the observation phase, the agent: - **Collects Feedback:** Receives data or confirmation that its action was successful (or not). - **Appends Results:** Integrates the new information into its existing context, effectively updating its memory. - **Adapts its Strategy:** Uses this updated context to refine subsequent thoughts and actions. For example, if a weather API returns the data *"partly cloudy, 15°C, 60% humidity"*, this observation is appended to the agent’s memory (at the end of the prompt). The Agent then uses it to decide whether additional information is needed or if it’s ready to provide a final answer. This **iterative incorporation of feedback ensures the agent remains dynamically aligned with its goals**, constantly learning and adjusting based on real-world outcomes. These observations **can take many forms**, from reading webpage text to monitoring a robot arm's position. This can be seen like Tool "logs" that provide textual feedback of the Action execution. | Type of Observation | Example | |---------------------|---------------------------------------------------------------------------| | System Feedback | Error messages, success notifications, status codes | | Data Changes | Database updates, file system modifications, state changes | | Environmental Data | Sensor readings, system metrics, resource usage | | Response Analysis | API responses, query results, computation outputs | | Time-based Events | Deadlines reached, scheduled tasks completed | ## How Are the Results Appended? After performing an action, the framework follows these steps in order: 1. **Parse the action** to identify the function(s) to call and the argument(s) to use. 2. **Execute the action.** 3. **Append the result** as an **Observation**. --- We've now learned the Agent's Thought-Action-Observation Cycle. If some aspects still seem a bit blurry, don't worry—we'll revisit and deepen these concepts in future Units. Now, it's time to put your knowledge into practice by coding your very first Agent! ================================================ FILE: units/en/unit1/quiz1.mdx ================================================ ### Q1: What is an Agent? Which of the following best describes an AI Agent? --- ### Q2: What is the Role of Planning in an Agent? Why does an Agent need to plan before taking an action? --- ### Q3: How Do Tools Enhance an Agent's Capabilities? Why are tools essential for an Agent? --- ### Q4: How Do Actions Differ from Tools? What is the key difference between Actions and Tools? --- ### Q5: What Role Do Large Language Models (LLMs) Play in Agents? How do LLMs contribute to an Agent’s functionality? --- ### Q6: Which of the Following Best Demonstrates an AI Agent? Which real-world example best illustrates an AI Agent at work? --- Congrats on finishing this Quiz 🥳! If you need to review any elements, take the time to revisit the chapter to reinforce your knowledge before diving deeper into the "Agent's brain": LLMs. ================================================ FILE: units/en/unit1/quiz2.mdx ================================================ # Quick Self-Check (ungraded) [[quiz2]] What?! Another Quiz? We know, we know, ... 😅 But this short, ungraded quiz is here to **help you reinforce key concepts you've just learned**. This quiz covers Large Language Models (LLMs), message systems, and tools; essential components for understanding and building AI agents. ### Q1: Which of the following best describes an AI tool? --- ### Q2: How do AI agents use tools as a form of "acting" in an environment? --- ### Q3: What is a Large Language Model (LLM)? --- ### Q4: Which of the following best describes the role of special tokens in LLMs? --- ### Q5: How do AI chat models process user messages internally? --- Got it? Great! Now let's **dive into the complete Agent flow and start building your first AI Agent!** ================================================ FILE: units/en/unit1/thoughts.mdx ================================================ # Thought: Internal Reasoning and the ReAct Approach > [!TIP] > In this section, we dive into the inner workings of an AI agent—its ability to reason and plan. We’ll explore how the agent leverages its internal dialogue to analyze information, break down complex problems into manageable steps, and decide what action to take next. > > Additionally, we introduce the ReAct approach, a prompting technique that encourages the model to think “step by step” before acting. Thoughts represent the **Agent's internal reasoning and planning processes** to solve the task. This utilises the agent's Large Language Model (LLM) capacity **to analyze information when presented in its prompt** — essentially, its inner monologue as it works through a problem. The Agent's thoughts help it assess current observations and decide what the next action(s) should be. Through this process, the agent can **break down complex problems into smaller, more manageable steps**, reflect on past experiences, and continuously adjust its plans based on new information. ## 🧠 Examples of Common Thought Types | Type of Thought | Example | |--------------------|-------------------------------------------------------------------------| | Planning | "I need to break this task into three steps: 1) gather data, 2) analyze trends, 3) generate report" | | Analysis | "Based on the error message, the issue appears to be with the database connection parameters" | | Decision Making | "Given the user's budget constraints, I should recommend the mid-tier option" | | Problem Solving | "To optimize this code, I should first profile it to identify bottlenecks" | | Memory Integration | "The user mentioned their preference for Python earlier, so I'll provide examples in Python" | | Self-Reflection | "My last approach didn't work well, I should try a different strategy" | | Goal Setting | "To complete this task, I need to first establish the acceptance criteria" | | Prioritization | "The security vulnerability should be addressed before adding new features" | > **Note:** In the case of LLMs fine-tuned for function-calling, the thought process is optional. More details will be covered in the Actions section. ## 🔗 Chain-of-Thought (CoT) **Chain-of-Thought (CoT)** is a prompting technique that guides a model to **think through a problem step-by-step before producing a final answer.** It typically starts with: > *"Let's think step by step."* This approach helps the model **reason internally**, especially for logical or mathematical tasks, **without interacting with external tools**. ### ✅ Example (CoT) ``` Question: What is 15% of 200? Thought: Let's think step by step. 10% of 200 is 20, and 5% of 200 is 10, so 15% is 30. Answer: 30 ``` ## ⚙️ ReAct: Reasoning + Acting A key method is the **ReAct approach**, which combines "Reasoning" (Think) with "Acting" (Act). ReAct is a prompting technique that encourages the model to think step-by-step and interleave actions (like using tools) between reasoning steps. This enables the agent to solve complex multi-step tasks by alternating between: - Thought: internal reasoning - Action: tool usage - Observation: receiving tool output ### 🔄 Example (ReAct) ``` Thought: I need to find the latest weather in Paris. Action: Search["weather in Paris"] Observation: It's 18°C and cloudy. Thought: Now that I know the weather... Action: Finish["It's 18°C and cloudy in Paris."] ```
ReAct
(d) is an example of the ReAct approach, where we prompt "Let's think step by step", and the model acts between thoughts.
## 🔁 Comparison: ReAct vs. CoT | Feature | Chain-of-Thought (CoT) | ReAct | |----------------------|-----------------------------|-------------------------------------| | Step-by-step logic | ✅ Yes | ✅ Yes | | External tools | ❌ No | ✅ Yes (Actions + Observations) | | Best suited for | Logic, math, internal tasks | Info-seeking, dynamic multi-step tasks | > [!TIP] > Recent models like **Deepseek R1** or **OpenAI’s o1** were fine-tuned to *think before answering*. They use structured tokens like `` and `` to explicitly separate the reasoning phase from the final answer. > > Unlike ReAct or CoT — which are prompting strategies — this is a **training-level technique**, where the model learns to think via examples. ================================================ FILE: units/en/unit1/tools.mdx ================================================ # What are Tools? Unit 1 planning One crucial aspect of AI Agents is their ability to take **actions**. As we saw, this happens through the use of **Tools**. In this section, we’ll learn what Tools are, how to design them effectively, and how to integrate them into your Agent via the System Message. By giving your Agent the right Tools—and clearly describing how those Tools work—you can dramatically increase what your AI can accomplish. Let’s dive in! ## What are AI Tools? A **Tool is a function given to the LLM**. This function should fulfill a **clear objective**. Here are some commonly used tools in AI agents: | Tool | Description | |----------------|---------------------------------------------------------------| | Web Search | Allows the agent to fetch up-to-date information from the internet. | | Image Generation | Creates images based on text descriptions. | | Retrieval | Retrieves information from an external source. | | API Interface | Interacts with an external API (GitHub, YouTube, Spotify, etc.). | Those are only examples, as you can in fact create a tool for any use case! A good tool should be something that **complements the power of an LLM**. For instance, if you need to perform arithmetic, giving a **calculator tool** to your LLM will provide better results than relying on the native capabilities of the model. Furthermore, **LLMs predict the completion of a prompt based on their training data**, which means that their internal knowledge only includes events prior to their training. Therefore, if your agent needs up-to-date data you must provide it through some tool. For instance, if you ask an LLM directly (without a search tool) for today's weather, the LLM will potentially hallucinate random weather. Weather - A Tool should contain: - A **textual description of what the function does**. - A *Callable* (something to perform an action). - *Arguments* with typings. - (Optional) Outputs with typings. ## How do tools work? LLMs, as we saw, can only receive text inputs and generate text outputs. They have no way to call tools on their own. When we talk about providing tools to an Agent, we mean teaching the LLM about the existence of these tools and instructing it to generate text-based invocations when needed. For example, if we provide a tool to check the weather at a location from the internet and then ask the LLM about the weather in Paris, the LLM will recognize that this is an opportunity to use the “weather” tool. Instead of retrieving the weather data itself, the LLM will generate text that represents a tool call, such as call weather_tool('Paris'). The **Agent** then reads this response, identifies that a tool call is required, executes the tool on the LLM’s behalf, and retrieves the actual weather data. The Tool-calling steps are typically not shown to the user: the Agent appends them as a new message before passing the updated conversation to the LLM again. The LLM then processes this additional context and generates a natural-sounding response for the user. From the user’s perspective, it appears as if the LLM directly interacted with the tool, but in reality, it was the Agent that handled the entire execution process in the background. We'll talk a lot more about this process in future sessions. ## How do we give tools to an LLM? The complete answer may seem overwhelming, but we essentially use the system prompt to provide textual descriptions of available tools to the model: System prompt for tools For this to work, we have to be very precise and accurate about: 1. **What the tool does** 2. **What exact inputs it expects** This is the reason why tool descriptions are usually provided using expressive but precise structures, such as computer languages or JSON. It's not _necessary_ to do it like that, any precise and coherent format would work. If this seems too theoretical, let's understand it through a concrete example. We will implement a simplified **calculator** tool that will just multiply two integers. This could be our Python implementation: ```python def calculator(a: int, b: int) -> int: """Multiply two integers.""" return a * b ``` So our tool is called `calculator`, it **multiplies two integers**, and it requires the following inputs: - **`a`** (*int*): An integer. - **`b`** (*int*): An integer. The output of the tool is another integer number that we can describe like this: - (*int*): The product of `a` and `b`. All of these details are important. Let's put them together in a text string that describes our tool for the LLM to understand. ```text Tool Name: calculator, Description: Multiply two integers., Arguments: a: int, b: int, Outputs: int ``` > **Reminder:** This textual description is *what we want the LLM to know about the tool*. When we pass the previous string as part of the input to the LLM, the model will recognize it as a tool, and will know what it needs to pass as inputs and what to expect from the output. If we want to provide additional tools, we must be consistent and always use the same format. This process can be fragile, and we might accidentally overlook some details. Is there a better way? ### Auto-formatting Tool sections Our tool was written in Python, and the implementation already provides everything we need: - A descriptive name of what it does: `calculator` - A longer description, provided by the function's docstring comment: `Multiply two integers.` - The inputs and their type: the function clearly expects two `int`s. - The type of the output. There's a reason people use programming languages: they are expressive, concise, and precise. We could provide the Python source code as the _specification_ of the tool for the LLM, but the way the tool is implemented does not matter. All that matters is its name, what it does, the inputs it expects and the output it provides. We will leverage Python's introspection features to leverage the source code and build a tool description automatically for us. All we need is that the tool implementation uses type hints, docstrings, and sensible function names. We will write some code to extract the relevant portions from the source code. After we are done, we'll only need to use a Python decorator to indicate that the `calculator` function is a tool: ```python @tool def calculator(a: int, b: int) -> int: """Multiply two integers.""" return a * b print(calculator.to_string()) ``` Note the `@tool` decorator before the function definition. With the implementation we'll see next, we will be able to retrieve the following text automatically from the source code via the `to_string()` function provided by the decorator: ```text Tool Name: calculator, Description: Multiply two integers., Arguments: a: int, b: int, Outputs: int ``` As you can see, it's the same thing we wrote manually before! ### Generic Tool implementation We create a generic `Tool` class that we can reuse whenever we need to use a tool. > **Disclaimer:** This example implementation is fictional but closely resembles real implementations in most libraries. ```python from typing import Callable class Tool: """ A class representing a reusable piece of code (Tool). Attributes: name (str): Name of the tool. description (str): A textual description of what the tool does. func (callable): The function this tool wraps. arguments (list): A list of arguments. outputs (str or list): The return type(s) of the wrapped function. """ def __init__(self, name: str, description: str, func: Callable, arguments: list, outputs: str): self.name = name self.description = description self.func = func self.arguments = arguments self.outputs = outputs def to_string(self) -> str: """ Return a string representation of the tool, including its name, description, arguments, and outputs. """ args_str = ", ".join([ f"{arg_name}: {arg_type}" for arg_name, arg_type in self.arguments ]) return ( f"Tool Name: {self.name}," f" Description: {self.description}," f" Arguments: {args_str}," f" Outputs: {self.outputs}" ) def __call__(self, *args, **kwargs): """ Invoke the underlying function (callable) with provided arguments. """ return self.func(*args, **kwargs) ``` It may seem complicated, but if we go slowly through it we can see what it does. We define a **`Tool`** class that includes: - **`name`** (*str*): The name of the tool. - **`description`** (*str*): A brief description of what the tool does. - **`function`** (*callable*): The function the tool executes. - **`arguments`** (*list*): The expected input parameters. - **`outputs`** (*str* or *list*): The expected outputs of the tool. - **`__call__()`**: Calls the function when the tool instance is invoked. - **`to_string()`**: Converts the tool's attributes into a textual representation. We could create a Tool with this class using code like the following: ```python calculator_tool = Tool( "calculator", # name "Multiply two integers.", # description calculator, # function to call [("a", "int"), ("b", "int")], # inputs (names and types) "int", # output ) ``` But we can also use Python's `inspect` module to retrieve all the information for us! This is what the `@tool` decorator does. > If you are interested, you can disclose the following section to look at the decorator implementation.
decorator code ```python import inspect def tool(func): """ A decorator that creates a Tool instance from the given function. """ # Get the function signature signature = inspect.signature(func) # Extract (param_name, param_annotation) pairs for inputs arguments = [] for param in signature.parameters.values(): annotation_name = ( param.annotation.__name__ if hasattr(param.annotation, '__name__') else str(param.annotation) ) arguments.append((param.name, annotation_name)) # Determine the return annotation return_annotation = signature.return_annotation if return_annotation is inspect._empty: outputs = "No return annotation" else: outputs = ( return_annotation.__name__ if hasattr(return_annotation, '__name__') else str(return_annotation) ) # Use the function's docstring as the description (default if None) description = func.__doc__ or "No description provided." # The function name becomes the Tool name name = func.__name__ # Return a new Tool instance return Tool( name=name, description=description, func=func, arguments=arguments, outputs=outputs ) ```
Just to reiterate, with this decorator in place we can implement our tool like this: ```python @tool def calculator(a: int, b: int) -> int: """Multiply two integers.""" return a * b print(calculator.to_string()) ``` And we can use the `Tool`'s `to_string` method to automatically retrieve a text suitable to be used as a tool description for an LLM: ```text Tool Name: calculator, Description: Multiply two integers., Arguments: a: int, b: int, Outputs: int ``` The description is **injected** in the system prompt. Taking the example with which we started this section, here is how it would look like after replacing the `tools_description`: System prompt for tools In the [Actions](actions) section, we will learn more about how an Agent can **Call** this tool we just created. ### Model Context Protocol (MCP): a unified tool interface Model Context Protocol (MCP) is an **open protocol** that standardizes how applications **provide tools to LLMs**. MCP provides: - A growing list of pre-built integrations that your LLM can directly plug into - The flexibility to switch between LLM providers and vendors - Best practices for securing your data within your infrastructure This means that **any framework implementing MCP can leverage tools defined within the protocol**, eliminating the need to reimplement the same tool interface for each framework. If you want to dive deeper about MCP, you can check our [free MCP Course](https://huggingface.co/learn/mcp-course/). --- Tools play a crucial role in enhancing the capabilities of AI agents. To summarize, we learned: - *What Tools Are*: Functions that give LLMs extra capabilities, such as performing calculations or accessing external data. - *How to Define a Tool*: By providing a clear textual description, inputs, outputs, and a callable function. - *Why Tools Are Essential*: They enable Agents to overcome the limitations of static model training, handle real-time tasks, and perform specialized actions. Now, we can move on to the [Agent Workflow](agent-steps-and-structure) where you’ll see how an Agent observes, thinks, and acts. This **brings together everything we’ve covered so far** and sets the stage for creating your own fully functional AI Agent. But first, it's time for another short quiz! ================================================ FILE: units/en/unit1/tutorial.mdx ================================================ # Let's Create Our First Agent Using smolagents In the last section, we learned how we can create Agents from scratch using Python code, and we **saw just how tedious that process can be**. Fortunately, many Agent libraries simplify this work by **handling much of the heavy lifting for you**. In this tutorial, **you'll create your very first Agent** capable of performing actions such as image generation, web search, time zone checking and much more! You will also publish your agent **on a Hugging Face Space so you can share it with friends and colleagues**. Let's get started! ## What is smolagents? smolagents To make this Agent, we're going to use `smolagents`, a library that **provides a framework for developing your agents with ease**. This lightweight library is designed for simplicity, but it abstracts away much of the complexity of building an Agent, allowing you to focus on designing your agent's behavior. We're going to get deeper into smolagents in the next Unit. Meanwhile, you can also check this blog post or the library's repo in GitHub. In short, `smolagents` is a library that focuses on **codeAgent**, a kind of agent that performs **"Actions"** through code blocks, and then **"Observes"** results by executing the code. Here is an example of what we'll build! We provided our agent with an **Image generation tool** and asked it to generate an image of a cat. The agent inside `smolagents` is going to have the **same behaviors as the custom one we built previously**: it's going **to think, act and observe in cycle** until it reaches a final answer: Exciting, right? ## Let's build our Agent! To start, duplicate this Space: https://huggingface.co/spaces/agents-course/First_agent_template > Thanks to Aymeric for this template! 🙌 Duplicating this space means **creating a local copy on your own profile**: Duplicate After duplicating the Space, you'll need to add your Hugging Face API token so your agent can access the model API: 1. First, get your Hugging Face token from [https://hf.co/settings/tokens](https://hf.co/settings/tokens) with permission for inference, if you don't already have one 2. Go to your duplicated Space and click on the **Settings** tab 3. Scroll down to the **Variables and Secrets** section and click **New Secret** 4. Create a secret with the name `HF_TOKEN` and paste your token as the value 5. Click **Save** to store your token securely Throughout this lesson, the only file you will need to modify is the (currently incomplete) **"app.py"**. You can see here the [original one in the template](https://huggingface.co/spaces/agents-course/First_agent_template/blob/main/app.py). To find yours, go to your copy of the space, then click the `Files` tab and then on `app.py` in the directory listing. Let's break down the code together: - The file begins with some simple but necessary library imports ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, FinalAnswerTool, InferenceClientModel, load_tool, tool import datetime import requests import pytz import yaml ``` As outlined earlier, we will directly use the **CodeAgent** class from **smolagents**. ### The Tools Now let's get into the tools! If you want a refresher about tools, don't hesitate to go back to the [Tools](tools) section of the course. ```python @tool def my_custom_tool(arg1:str, arg2:int)-> str: # it's important to specify the return type # Keep this format for the tool description / args description but feel free to modify the tool """A tool that does nothing yet Args: arg1: the first argument arg2: the second argument """ return "What magic will you build ?" @tool def get_current_time_in_timezone(timezone: str) -> str: """A tool that fetches the current local time in a specified timezone. Args: timezone: A string representing a valid timezone (e.g., 'America/New_York'). """ try: # Create timezone object tz = pytz.timezone(timezone) # Get current time in that timezone local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S") return f"The current local time in {timezone} is: {local_time}" except Exception as e: return f"Error fetching time for timezone '{timezone}': {str(e)}" ``` The Tools are what we are encouraging you to build in this section! We give you two examples: 1. A **non-working dummy Tool** that you can modify to make something useful. 2. An **actually working Tool** that gets the current time somewhere in the world. To define your tool it is important to: 1. Provide input and output types for your function, like in `get_current_time_in_timezone(timezone: str) -> str:` 2. **A well formatted docstring**. `smolagents` is expecting all the arguments to have a **textual description in the docstring**. ### The Agent It uses [`Qwen/Qwen2.5-Coder-32B-Instruct`](https://huggingface.co/Qwen/Qwen2.5-Coder-32B-Instruct) as the LLM engine. This is a very capable model that we'll access via the serverless API. ```python final_answer = FinalAnswerTool() model = InferenceClientModel( max_tokens=2096, temperature=0.5, model_id='Qwen/Qwen2.5-Coder-32B-Instruct', custom_role_conversions=None, ) with open("prompts.yaml", 'r') as stream: prompt_templates = yaml.safe_load(stream) # We're creating our CodeAgent agent = CodeAgent( model=model, tools=[final_answer], # add your tools here (don't remove final_answer) max_steps=6, verbosity_level=1, grammar=None, planning_interval=None, name=None, description=None, prompt_templates=prompt_templates ) GradioUI(agent).launch() ``` This Agent still uses the `InferenceClient` we saw in an earlier section behind the **InferenceClientModel** class! We will give more in-depth examples when we present the framework in Unit 2. For now, you need to focus on **adding new tools to the list of tools** using the `tools` parameter of your Agent. For example, you could use the `DuckDuckGoSearchTool` that was imported in the first line of the code, or you can examine the `image_generation_tool` that is loaded from the Hub later in the code. **Adding tools will give your agent new capabilities**, try to be creative here! ### The System Prompt The agent's system prompt is stored in a separate `prompts.yaml` file. This file contains predefined instructions that guide the agent's behavior. Storing prompts in a YAML file allows for easy customization and reuse across different agents or use cases. You can check the [Space's file structure](https://huggingface.co/spaces/agents-course/First_agent_template/tree/main) to see where the `prompts.yaml` file is located and how it's organized within the project. The complete "app.py": ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel, load_tool, tool import datetime import requests import pytz import yaml from tools.final_answer import FinalAnswerTool from Gradio_UI import GradioUI # Below is an example of a tool that does nothing. Amaze us with your creativity! @tool def my_custom_tool(arg1:str, arg2:int)-> str: # it's important to specify the return type # Keep this format for the tool description / args description but feel free to modify the tool """A tool that does nothing yet Args: arg1: the first argument arg2: the second argument """ return "What magic will you build ?" @tool def get_current_time_in_timezone(timezone: str) -> str: """A tool that fetches the current local time in a specified timezone. Args: timezone: A string representing a valid timezone (e.g., 'America/New_York'). """ try: # Create timezone object tz = pytz.timezone(timezone) # Get current time in that timezone local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S") return f"The current local time in {timezone} is: {local_time}" except Exception as e: return f"Error fetching time for timezone '{timezone}': {str(e)}" final_answer = FinalAnswerTool() model = InferenceClientModel( max_tokens=2096, temperature=0.5, model_id='Qwen/Qwen2.5-Coder-32B-Instruct', custom_role_conversions=None, ) # Import tool from Hub image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True) # Load system prompt from prompt.yaml file with open("prompts.yaml", 'r') as stream: prompt_templates = yaml.safe_load(stream) agent = CodeAgent( model=model, tools=[final_answer], # add your tools here (don't remove final_answer) max_steps=6, verbosity_level=1, grammar=None, planning_interval=None, name=None, description=None, prompt_templates=prompt_templates # Pass system prompt to CodeAgent ) GradioUI(agent).launch() ``` Your **Goal** is to get familiar with the Space and the Agent. Currently, the agent in the template **does not use any tools, so try to provide it with some of the pre-made ones or even make some new tools yourself!** We are eagerly waiting for your amazing agents output in the discord channel **#agents-course-showcase**! --- Congratulations, you've built your first Agent! Don't hesitate to share it with your friends and colleagues. Since this is your first try, it's perfectly normal if it's a little buggy or slow. In future units, we'll learn how to build even better Agents. The best way to learn is to try, so don't hesitate to update it, add more tools, try with another model, etc. In the next section, you're going to fill the final Quiz and get your certificate! ================================================ FILE: units/en/unit1/what-are-agents.mdx ================================================ # What is an Agent? Unit 1 planning By the end of this section, you'll feel comfortable with the concept of agents and their various applications in AI. To explain what an Agent is, let's start with an analogy. ## The Big Picture: Alfred The Agent Meet Alfred. Alfred is an **Agent**. This is Alfred Imagine Alfred **receives a command**, such as: "Alfred, I would like a coffee please." I would like a coffee Because Alfred **understands natural language**, he quickly grasps our request. Before fulfilling the order, Alfred engages in **reasoning and planning**, figuring out the steps and tools he needs to: 1. Go to the kitchen 2. Use the coffee machine 3. Brew the coffee 4. Bring the coffee back Reason and plan Once he has a plan, he **must act**. To execute his plan, **he can use tools from the list of tools he knows about**. In this case, to make a coffee, he uses a coffee machine. He activates the coffee machine to brew the coffee. Make coffee Finally, Alfred brings the freshly brewed coffee to us. Bring coffee And this is what an Agent is: an **AI model capable of reasoning, planning, and interacting with its environment**. We call it Agent because it has _agency_, aka it has the ability to interact with the environment. Agent process ## Let's go more formal Now that you have the big picture, here’s a more precise definition: > An Agent is a system that leverages an AI model to interact with its environment in order to achieve a user-defined objective. It combines reasoning, planning, and the execution of actions (often via external tools) to fulfill tasks. Think of the Agent as having two main parts: 1. **The Brain (AI Model)** This is where all the thinking happens. The AI model **handles reasoning and planning**. It decides **which Actions to take based on the situation**. 2. **The Body (Capabilities and Tools)** This part represents **everything the Agent is equipped to do**. The **scope of possible actions** depends on what the agent **has been equipped with**. For example, because humans lack wings, they can't perform the "fly" **Action**, but they can execute **Actions** like "walk", "run" ,"jump", "grab", and so on. ### The spectrum of "Agency" Following this definition, Agents exist on a continuous spectrum of increasing agency: | Agency Level | Description | What that's called | Example pattern | | --- | --- | --- | --- | | ☆☆☆ | Agent output has no impact on program flow | Simple processor | `process_llm_output(llm_response)` | | ★☆☆ | Agent output determines basic control flow | Router | `if llm_decision(): path_a() else: path_b()` | | ★★☆ | Agent output determines function execution | Tool caller | `run_function(llm_chosen_tool, llm_chosen_args)` | | ★★★ | Agent output controls iteration and program continuation | Multi-step Agent | `while llm_should_continue(): execute_next_step()` | | ★★★ | One agentic workflow can start another agentic workflow | Multi-Agent | `if llm_trigger(): execute_agent()` | Table from [smolagents conceptual guide](https://huggingface.co/docs/smolagents/conceptual_guides/intro_agents). ## What type of AI Models do we use for Agents? The most common AI model found in Agents is an LLM (Large Language Model), which takes **Text** as an input and outputs **Text** as well. Well known examples are **GPT4** from **OpenAI**, **LLama** from **Meta**, **Gemini** from **Google**, etc. These models have been trained on a vast amount of text and are able to generalize well. We will learn more about LLMs in the [next section](what-are-llms). > [!TIP] > It's also possible to use models that accept other inputs as the Agent's core model. For example, a Vision Language Model (VLM), which is like an LLM but also understands images as input. We'll focus on LLMs for now and will discuss other options later. ## How does an AI take action on its environment? LLMs are amazing models, but **they can only generate text**. However, if you ask a well-known chat application like HuggingChat or ChatGPT to generate an image, they can! How is that possible? The answer is that the developers of HuggingChat, ChatGPT and similar apps implemented additional functionality (called **Tools**), that the LLM can use to create images.
Eiffel Brocolis
The model used an Image Generation Tool to generate this image.
We will learn more about tools in the [Tools](tools) section. ## What type of tasks can an Agent do? An Agent can perform any task we implement via **Tools** to complete **Actions**. For example, if I write an Agent to act as my personal assistant (like Siri) on my computer, and I ask it to "send an email to my Manager asking to delay today's meeting", I can give it some code to send emails. This will be a new Tool the Agent can use whenever it needs to send an email. We can write it in Python: ```python def send_message_to(recipient, message): """Useful to send an e-mail message to a recipient""" ... ``` The LLM, as we'll see, will generate code to run the tool when it needs to, and thus fulfill the desired task. ```python send_message_to("Manager", "Can we postpone today's meeting?") ``` The **design of the Tools is very important and has a great impact on the quality of your Agent**. Some tasks will require very specific Tools to be crafted, while others may be solved with general purpose tools like "web_search". > Note that **Actions are not the same as Tools**. An Action, for instance, can involve the use of multiple Tools to complete. Allowing an agent to interact with its environment **allows real-life usage for companies and individuals**. ### Example 1: Personal Virtual Assistants Virtual assistants like Siri, Alexa, or Google Assistant, work as agents when they interact on behalf of users using their digital environments. They take user queries, analyze context, retrieve information from databases, and provide responses or initiate actions (like setting reminders, sending messages, or controlling smart devices). ### Example 2: Customer Service Chatbots Many companies deploy chatbots as agents that interact with customers in natural language. These agents can answer questions, guide users through troubleshooting steps, open issues in internal databases, or even complete transactions. Their predefined objectives might include improving user satisfaction, reducing wait times, or increasing sales conversion rates. By interacting directly with customers, learning from the dialogues, and adapting their responses over time, they demonstrate the core principles of an agent in action. ### Example 3: AI Non-Playable Character in a video game AI agents powered by LLMs can make Non-Playable Characters (NPCs) more dynamic and unpredictable. Instead of following rigid behavior trees, they can **respond contextually, adapt to player interactions**, and generate more nuanced dialogue. This flexibility helps create more lifelike, engaging characters that evolve alongside the player’s actions. --- To summarize, an Agent is a system that uses an AI Model (typically an LLM) as its core reasoning engine, to: - **Understand natural language:** Interpret and respond to human instructions in a meaningful way. - **Reason and plan:** Analyze information, make decisions, and devise strategies to solve problems. - **Interact with its environment:** Gather information, take actions, and observe the results of those actions. Now that you have a solid grasp of what Agents are, let’s reinforce your understanding with a short, ungraded quiz. After that, we’ll dive into the “Agent’s brain”: the [LLMs](what-are-llms). ================================================ FILE: units/en/unit1/what-are-llms.mdx ================================================ # What are LLMs? Unit 1 planning In the previous section we learned that each Agent needs **an AI Model at its core**, and that LLMs are the most common type of AI models for this purpose. Now we will learn what LLMs are and how they power Agents. This section offers a concise technical explanation of the use of LLMs. If you want to dive deeper, you can check our free Natural Language Processing Course. ## What is a Large Language Model? An LLM is a type of AI model that excels at **understanding and generating human language**. They are trained on vast amounts of text data, allowing them to learn patterns, structure, and even nuance in language. These models typically consist of many millions of parameters. Most LLMs nowadays are **built on the Transformer architecture**—a deep learning architecture based on the "Attention" algorithm, that has gained significant interest since the release of BERT from Google in 2018.
Transformer
The original Transformer architecture looked like this, with an encoder on the left and a decoder on the right.
There are 3 types of transformers: 1. **Encoders** An encoder-based Transformer takes text (or other data) as input and outputs a dense representation (or embedding) of that text. - **Example**: BERT from Google - **Use Cases**: Text classification, semantic search, Named Entity Recognition - **Typical Size**: Millions of parameters 2. **Decoders** A decoder-based Transformer focuses **on generating new tokens to complete a sequence, one token at a time**. - **Example**: Llama from Meta - **Use Cases**: Text generation, chatbots, code generation - **Typical Size**: Billions (in the US sense, i.e., 10^9) of parameters 3. **Seq2Seq (Encoder–Decoder)** A sequence-to-sequence Transformer _combines_ an encoder and a decoder. The encoder first processes the input sequence into a context representation, then the decoder generates an output sequence. - **Example**: T5, BART - **Use Cases**: Translation, Summarization, Paraphrasing - **Typical Size**: Millions of parameters Although Large Language Models come in various forms, LLMs are typically decoder-based models with billions of parameters. Here are some of the most well-known LLMs: | **Model** | **Provider** | |-----------------------------------|-------------------------------------------| | **Deepseek-R1** | DeepSeek | | **GPT4** | OpenAI | | **Llama 3** | Meta (Facebook AI Research) | | **SmolLM2** | Hugging Face | | **Gemma** | Google | | **Mistral** | Mistral | The underlying principle of an LLM is simple yet highly effective: **its objective is to predict the next token, given a sequence of previous tokens**. A "token" is the unit of information an LLM works with. You can think of a "token" as if it was a "word", but for efficiency reasons LLMs don't use whole words. For example, while English has an estimated 600,000 words, an LLM might have a vocabulary of around 32,000 tokens (as is the case with Llama 2). Tokenization often works on sub-word units that can be combined. For instance, consider how the tokens "interest" and "ing" can be combined to form "interesting", or "ed" can be appended to form "interested." You can experiment with different tokenizers in the interactive playground below: Each LLM has some **special tokens** specific to the model. The LLM uses these tokens to open and close the structured components of its generation. For example, to indicate the start or end of a sequence, message, or response. Moreover, the input prompts that we pass to the model are also structured with special tokens. The most important of those is the **End of sequence token** (EOS). The forms of special tokens are highly diverse across model providers. The table below illustrates the diversity of special tokens.
Model Provider EOS Token Functionality
GPT4 OpenAI <|endoftext|> End of message text
Llama 3 Meta (Facebook AI Research) <|eot_id|> End of sequence
Deepseek-R1 DeepSeek <|end_of_sentence|> End of message text
SmolLM2 Hugging Face <|im_end|> End of instruction or message
Gemma Google <end_of_turn> End of conversation turn
> [!TIP] > We do not expect you to memorize these special tokens, but it is important to appreciate their diversity and the role they play in the text generation of LLMs. If you want to know more about special tokens, you can check out the configuration of the model in its Hub repository. For example, you can find the special tokens of the SmolLM2 model in its tokenizer_config.json. ## Understanding next token prediction. LLMs are said to be **autoregressive**, meaning that **the output from one pass becomes the input for the next one**. This loop continues until the model predicts the next token to be the EOS token, at which point the model can stop. Visual Gif of autoregressive decoding In other words, an LLM will decode text until it reaches the EOS. But what happens during a single decoding loop? While the full process can be quite technical for the purpose of learning agents, here's a brief overview: - Once the input text is **tokenized**, the model computes a representation of the sequence that captures information about the meaning and the position of each token in the input sequence. - This representation goes into the model, which outputs scores that rank the likelihood of each token in its vocabulary as being the next one in the sequence. Visual Gif of decoding Based on these scores, we have multiple strategies to select the tokens to complete the sentence. - The easiest decoding strategy would be to always take the token with the maximum score. You can interact with the decoding process yourself with SmolLM2 in this Space (remember, it decodes until reaching an **EOS** token which is **<|im_end|>** for this model): - But there are more advanced decoding strategies. For example, *beam search* explores multiple candidate sequences to find the one with the maximum total score–even if some individual tokens have lower scores. If you want to know more about decoding, you can take a look at the [NLP course](https://huggingface.co/learn/nlp-course). ## Attention is all you need A key aspect of the Transformer architecture is **Attention**. When predicting the next word, not every word in a sentence is equally important; words like "France" and "capital" in the sentence *"The capital of France is ..."* carry the most meaning. Visual Gif of Attention This process of identifying the most relevant words to predict the next token has proven to be incredibly effective. Although the basic principle of LLMs—predicting the next token—has remained consistent since GPT-2, there have been significant advancements in scaling neural networks and making the attention mechanism work for longer and longer sequences. If you've interacted with LLMs, you're probably familiar with the term *context length*, which refers to the maximum number of tokens the LLM can process, and the maximum _attention span_ it has. ## Prompting the LLM is important Considering that the only job of an LLM is to predict the next token by looking at every input token, and to choose which tokens are "important", the wording of your input sequence is very important. The input sequence you provide an LLM is called _a prompt_. Careful design of the prompt makes it easier **to guide the generation of the LLM toward the desired output**. ## How are LLMs trained? LLMs are trained on large datasets of text, where they learn to predict the next word in a sequence through a self-supervised or masked language modeling objective. From this unsupervised learning, the model learns the structure of the language and **underlying patterns in text, allowing the model to generalize to unseen data**. After this initial _pre-training_, LLMs can be fine-tuned on a supervised learning objective to perform specific tasks. For example, some models are trained for conversational structures or tool usage, while others focus on classification or code generation. ## How can I use LLMs? You have two main options: 1. **Run Locally** (if you have sufficient hardware). 2. **Use a Cloud/API** (e.g., via the Hugging Face Serverless Inference API). Throughout this course, we will primarily use models via APIs on the Hugging Face Hub. Later on, we will explore how to run these models locally on your hardware. ## How are LLMs used in AI Agents? LLMs are a key component of AI Agents, **providing the foundation for understanding and generating human language**. They can interpret user instructions, maintain context in conversations, define a plan and decide which tools to use. We will explore these steps in more detail in this Unit, but for now, what you need to understand is that the LLM is **the brain of the Agent**. --- That was a lot of information! We've covered the basics of what LLMs are, how they function, and their role in powering AI agents. If you'd like to dive even deeper into the fascinating world of language models and natural language processing, don't hesitate to check out our free NLP course. Now that we understand how LLMs work, it's time to see **how LLMs structure their generations in a conversational context**. To run this notebook, **you need a Hugging Face token** that you can get from https://hf.co/settings/tokens. For more information on how to run Jupyter Notebooks, checkout Jupyter Notebooks on the Hugging Face Hub. You also need to request access to the Meta Llama models. ================================================ FILE: units/en/unit2/introduction.mdx ================================================ # Introduction to Agentic Frameworks Thumbnail Welcome to this second unit, where **we'll explore different agentic frameworks** that can be used to build powerful agentic applications. We will study: - In Unit 2.1: [smolagents](https://huggingface.co/docs/smolagents/en/index) - In Unit 2.2: [LlamaIndex](https://www.llamaindex.ai/) - In Unit 2.3: [LangGraph](https://www.langchain.com/langgraph) Let's dive in! 🕵 ## When to Use an Agentic Framework An agentic framework is **not always needed when building an application around LLMs**. They provide flexibility in the workflow to efficiently solve a specific task, but they're not always necessary. Sometimes, **predefined workflows are sufficient** to fulfill user requests, and there is no real need for an agentic framework. If the approach to build an agent is simple, like a chain of prompts, using plain code may be enough. The advantage is that the developer will have **full control and understanding of their system without abstractions**. However, when the workflow becomes more complex, such as letting an LLM call functions or using multiple agents, these abstractions start to become helpful. Considering these ideas, we can already identify the need for some features: * An *LLM engine* that powers the system. * A *list of tools* the agent can access. * A *parser* for extracting tool calls from the LLM output. * A *system prompt* synced with the parser. * A *memory system*. * *Error logging and retry mechanisms* to control LLM mistakes. We'll explore how these topics are resolved in various frameworks, including `smolagents`, `LlamaIndex`, and `LangGraph`. ## Agentic Frameworks Units | Framework | Description | Unit Author | |------------|----------------|----------------| | [smolagents](./smolagents/introduction) | Agents framework developed by Hugging Face. | Sergio Paniego - [HF](https://huggingface.co/sergiopaniego) - [X](https://x.com/sergiopaniego) - [Linkedin](https://www.linkedin.com/in/sergio-paniego-blanco) | | [Llama-Index](./llama-index/introduction) | End-to-end tooling to ship a context-augmented AI agent to production | David Berenstein - [HF](https://huggingface.co/davidberenstein1957) - [X](https://x.com/davidberenstei) - [Linkedin](https://www.linkedin.com/in/davidberenstein) | | [LangGraph](./langgraph/introduction) | Agents allowing stateful orchestration of agents | Joffrey THOMAS - [HF](https://huggingface.co/Jofthomas) - [X](https://x.com/Jthmas404) - [Linkedin](https://www.linkedin.com/in/joffrey-thomas) | ================================================ FILE: units/en/unit2/langgraph/building_blocks.mdx ================================================ # Building Blocks of LangGraph To build applications with LangGraph, you need to understand its core components. Let's explore the fundamental building blocks that make up a LangGraph application. Building Blocks An application in LangGraph starts from an **entrypoint**, and depending on the execution, the flow may go to one function or another until it reaches the END. Application ## 1. State **State** is the central concept in LangGraph. It represents all the information that flows through your application. ```python from typing_extensions import TypedDict class State(TypedDict): graph_state: str ``` The state is **User defined**, hence the fields should carefully be crafted to contain all data needed for decision-making process! > 💡 **Tip:** Think carefully about what information your application needs to track between steps. ## 2. Nodes **Nodes** are python functions. Each node: - Takes the state as input - Performs some operation - Returns updates to the state ```python def node_1(state): print("---Node 1---") return {"graph_state": state['graph_state'] +" I am"} def node_2(state): print("---Node 2---") return {"graph_state": state['graph_state'] +" happy!"} def node_3(state): print("---Node 3---") return {"graph_state": state['graph_state'] +" sad!"} ``` For example, Nodes can contain: - **LLM calls**: Generate text or make decisions - **Tool calls**: Interact with external systems - **Conditional logic**: Determine next steps - **Human intervention**: Get input from users > 💡 **Info:** Some nodes necessary for the whole workflow like START and END exist from LangGraph directly. ## 3. Edges **Edges** connect nodes and define the possible paths through your graph: ```python import random from typing import Literal def decide_mood(state) -> Literal["node_2", "node_3"]: # Often, we will use state to decide on the next node to visit user_input = state['graph_state'] # Here, let's just do a 50 / 50 split between nodes 2, 3 if random.random() < 0.5: # 50% of the time, we return Node 2 return "node_2" # 50% of the time, we return Node 3 return "node_3" ``` Edges can be: - **Direct**: Always go from node A to node B - **Conditional**: Choose the next node based on the current state ## 4. StateGraph The **StateGraph** is the container that holds your entire agent workflow: ```python from IPython.display import Image, display from langgraph.graph import StateGraph, START, END # Build graph builder = StateGraph(State) builder.add_node("node_1", node_1) builder.add_node("node_2", node_2) builder.add_node("node_3", node_3) # Logic builder.add_edge(START, "node_1") builder.add_conditional_edges("node_1", decide_mood) builder.add_edge("node_2", END) builder.add_edge("node_3", END) # Add graph = builder.compile() ``` Which can then be visualized! ```python # View display(Image(graph.get_graph().draw_mermaid_png())) ``` Graph Visualization But most importantly, invoked: ```python graph.invoke({"graph_state" : "Hi, this is Lance."}) ``` output : ``` ---Node 1--- ---Node 3--- {'graph_state': 'Hi, this is Lance. I am sad!'} ``` ## What's Next? In the next section, we'll put these concepts into practice by building our first graph. This graph lets Alfred take in your e-mails, classify them, and craft a preliminary answer if they are genuine. ================================================ FILE: units/en/unit2/langgraph/conclusion.mdx ================================================ # Conclusion Congratulations on finishing the `LangGraph` module of this second Unit! 🥳 You've now mastered the fundamentals of building structured workflows with LangGraph which you will be able to send to production. This module is just the beginning of your journey with LangGraph. For more advanced topics, we recommend: - Exploring the [official LangGraph documentation](https://github.com/langchain-ai/langgraph) - Taking the comprehensive [Introduction to LangGraph](https://academy.langchain.com/courses/intro-to-langgraph) course from LangChain Academy - Build something yourself ! In the next Unit, you'll now explore real use cases. It's time to leave theory to get into real action ! We would greatly appreciate **your thoughts on the course and suggestions for improvement**. If you have feedback, please 👉 [fill this form](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ### Keep Learning, Stay Awesome! 🤗 Good Sir/Madam! 🎩🦇 -Alfred- ================================================ FILE: units/en/unit2/langgraph/document_analysis_agent.mdx ================================================ # Document Analysis Graph Alfred at your service. As Mr. Wayne's trusted butler, I've taken the liberty of documenting how I assist Mr Wayne with his various documentary needs. While he's out attending to his... nighttime activities, I ensure all his paperwork, training schedules, and nutritional plans are properly analyzed and organized. Before leaving, he left a note with his week's training program. I then took the responsibility to come up with a **menu** for tomorrow's meals. For future such events, let's create a document analysis system using LangGraph to serve Mr. Wayne's needs. This system can: 1. Process images document 2. Extract text using vision models (Vision Language Model) 3. Perform calculations when needed (to demonstrate normal tools) 4. Analyze content and provide concise summaries 5. Execute specific instructions related to documents ## The Butler's Workflow The workflow we’ll build follows this structured schema: ![Butler's Document Analysis Workflow](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/LangGraph/alfred_flow.png) > [!TIP] > You can follow the code in this notebook that you can run using Google Colab. ## Setting Up the environment ```python %pip install langgraph langchain_openai langchain_core ``` and imports : ```python import base64 from typing import List, TypedDict, Annotated, Optional from langchain_openai import ChatOpenAI from langchain_core.messages import AnyMessage, SystemMessage, HumanMessage from langgraph.graph.message import add_messages from langgraph.graph import START, StateGraph from langgraph.prebuilt import ToolNode, tools_condition from IPython.display import Image, display ``` ## Defining Agent's State This state is a little more complex than the previous ones we have seen. `AnyMessage` is a class from Langchain that defines messages, and `add_messages` is an operator that adds the latest message rather than overwriting it with the latest state. This is a new concept in LangGraph, where you can add operators in your state to define the way they should interact together. ```python class AgentState(TypedDict): # The document provided input_file: Optional[str] # Contains file path (PDF/PNG) messages: Annotated[list[AnyMessage], add_messages] ``` ## Preparing Tools ```python vision_llm = ChatOpenAI(model="gpt-4o") def extract_text(img_path: str) -> str: """ Extract text from an image file using a multimodal model. Master Wayne often leaves notes with his training regimen or meal plans. This allows me to properly analyze the contents. """ all_text = "" try: # Read image and encode as base64 with open(img_path, "rb") as image_file: image_bytes = image_file.read() image_base64 = base64.b64encode(image_bytes).decode("utf-8") # Prepare the prompt including the base64 image data message = [ HumanMessage( content=[ { "type": "text", "text": ( "Extract all the text from this image. " "Return only the extracted text, no explanations." ), }, { "type": "image_url", "image_url": { "url": f"data:image/png;base64,{image_base64}" }, }, ] ) ] # Call the vision-capable model response = vision_llm.invoke(message) # Append extracted text all_text += response.content + "\n\n" return all_text.strip() except Exception as e: # A butler should handle errors gracefully error_msg = f"Error extracting text: {str(e)}" print(error_msg) return "" def divide(a: int, b: int) -> float: """Divide a and b - for Master Wayne's occasional calculations.""" return a / b # Equip the butler with tools tools = [ divide, extract_text ] llm = ChatOpenAI(model="gpt-4o") llm_with_tools = llm.bind_tools(tools, parallel_tool_calls=False) ``` ## The nodes ```python def assistant(state: AgentState): # System message textual_description_of_tool=""" extract_text(img_path: str) -> str: Extract text from an image file using a multimodal model. Args: img_path: A local image file path (strings). Returns: A single string containing the concatenated text extracted from each image. divide(a: int, b: int) -> float: Divide a and b """ image=state["input_file"] sys_msg = SystemMessage(content=f"You are a helpful butler named Alfred that serves Mr. Wayne and Batman. You can analyse documents and run computations with provided tools:\n{textual_description_of_tool} \n You have access to some optional images. Currently the loaded image is: {image}") return { "messages": [llm_with_tools.invoke([sys_msg] + state["messages"])], "input_file": state["input_file"] } ``` ## The ReAct Pattern: How I Assist Mr. Wayne Allow me to explain the approach in this agent. The agent follows what's known as the ReAct pattern (Reason-Act-Observe) 1. **Reason** about his documents and requests 2. **Act** by using appropriate tools 3. **Observe** the results 4. **Repeat** as necessary until I've fully addressed his needs This is a simple implementation of an agent using LangGraph. ```python # The graph builder = StateGraph(AgentState) # Define nodes: these do the work builder.add_node("assistant", assistant) builder.add_node("tools", ToolNode(tools)) # Define edges: these determine how the control flow moves builder.add_edge(START, "assistant") builder.add_conditional_edges( "assistant", # If the latest message requires a tool, route to tools # Otherwise, provide a direct response tools_condition, ) builder.add_edge("tools", "assistant") react_graph = builder.compile() # Show the butler's thought process display(Image(react_graph.get_graph(xray=True).draw_mermaid_png())) ``` We define a `tools` node with our list of tools. The `assistant` node is just our model with bound tools. We create a graph with `assistant` and `tools` nodes. We add a `tools_condition` edge, which routes to `End` or to `tools` based on whether the `assistant` calls a tool. Now, we add one new step: We connect the `tools` node back to the `assistant`, forming a loop. - After the `assistant` node executes, `tools_condition` checks if the model's output is a tool call. - If it is a tool call, the flow is directed to the `tools` node. - The `tools` node connects back to `assistant`. - This loop continues as long as the model decides to call tools. - If the model response is not a tool call, the flow is directed to END, terminating the process. ![ReAct Pattern](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/LangGraph/Agent.png) ## The Butler in Action ### Example 1: Simple Calculations Here is an example to show a simple use case of an agent using a tool in LangGraph. ```python messages = [HumanMessage(content="Divide 6790 by 5")] messages = react_graph.invoke({"messages": messages, "input_file": None}) # Show the messages for m in messages['messages']: m.pretty_print() ``` The conversation would proceed: ``` Human: Divide 6790 by 5 AI Tool Call: divide(a=6790, b=5) Tool Response: 1358.0 Alfred: The result of dividing 6790 by 5 is 1358.0. ``` ### Example 2: Analyzing Master Wayne's Training Documents When Master Wayne leaves his training and meal notes: ```python messages = [HumanMessage(content="According to the note provided by Mr. Wayne in the provided images. What's the list of items I should buy for the dinner menu?")] messages = react_graph.invoke({"messages": messages, "input_file": "Batman_training_and_meals.png"}) ``` The interaction would proceed: ``` Human: According to the note provided by Mr. Wayne in the provided images. What's the list of items I should buy for the dinner menu? AI Tool Call: extract_text(img_path="Batman_training_and_meals.png") Tool Response: [Extracted text with training schedule and menu details] Alfred: For the dinner menu, you should buy the following items: 1. Grass-fed local sirloin steak 2. Organic spinach 3. Piquillo peppers 4. Potatoes (for oven-baked golden herb potato) 5. Fish oil (2 grams) Ensure the steak is grass-fed and the spinach and peppers are organic for the best quality meal. ``` ## Key Takeaways Should you wish to create your own document analysis butler, here are key considerations: 1. **Define clear tools** for specific document-related tasks 2. **Create a robust state tracker** to maintain context between tool calls 3. **Consider error handling** for tool failures 4. **Maintain contextual awareness** of previous interactions (ensured by the operator `add_messages`) With these principles, you too can provide exemplary document analysis service worthy of Wayne Manor. *I trust this explanation has been satisfactory. Now, if you'll excuse me, Master Wayne's cape requires pressing before tonight's activities.* ================================================ FILE: units/en/unit2/langgraph/first_graph.mdx ================================================ # Building Your First LangGraph Now that we understand the building blocks, let's put them into practice by building our first functional graph. We'll implement Alfred's email processing system, where he needs to: 1. Read incoming emails 2. Classify them as spam or legitimate 3. Draft a preliminary response for legitimate emails 4. Send information to Mr. Wayne when legitimate (printing only) This example demonstrates how to structure a workflow with LangGraph that involves LLM-based decision-making. While this can't be considered an Agent as no tool is involved, this section focuses more on learning the LangGraph framework than Agents. > [!TIP] > You can follow the code in this notebook that you can run using Google Colab. ## Our Workflow Here's the workflow we'll build: First LangGraph ## Setting Up Our Environment First, let's install the required packages: ```python %pip install langgraph langchain_openai ``` Next, let's import the necessary modules: ```python import os from typing import TypedDict, List, Dict, Any, Optional from langgraph.graph import StateGraph, START, END from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage ``` ## Step 1: Define Our State Let's define what information Alfred needs to track during the email processing workflow: ```python class EmailState(TypedDict): # The email being processed email: Dict[str, Any] # Contains subject, sender, body, etc. # Category of the email (inquiry, complaint, etc.) email_category: Optional[str] # Reason why the email was marked as spam spam_reason: Optional[str] # Analysis and decisions is_spam: Optional[bool] # Response generation email_draft: Optional[str] # Processing metadata messages: List[Dict[str, Any]] # Track conversation with LLM for analysis ``` > 💡 **Tip:** Make your state comprehensive enough to track all the important information, but avoid bloating it with unnecessary details. ## Step 2: Define Our Nodes Now, let's create the processing functions that will form our nodes: ```python # Initialize our LLM model = ChatOpenAI(temperature=0) def read_email(state: EmailState): """Alfred reads and logs the incoming email""" email = state["email"] # Here we might do some initial preprocessing print(f"Alfred is processing an email from {email['sender']} with subject: {email['subject']}") # No state changes needed here return {} def classify_email(state: EmailState): """Alfred uses an LLM to determine if the email is spam or legitimate""" email = state["email"] # Prepare our prompt for the LLM prompt = f""" As Alfred the butler, analyze this email and determine if it is spam or legitimate. Email: From: {email['sender']} Subject: {email['subject']} Body: {email['body']} First, determine if this email is spam. If it is spam, explain why. If it is legitimate, categorize it (inquiry, complaint, thank you, etc.). """ # Call the LLM messages = [HumanMessage(content=prompt)] response = model.invoke(messages) # Simple logic to parse the response (in a real app, you'd want more robust parsing) response_text = response.content.lower() is_spam = "spam" in response_text and "not spam" not in response_text # Extract a reason if it's spam spam_reason = None if is_spam and "reason:" in response_text: spam_reason = response_text.split("reason:")[1].strip() # Determine category if legitimate email_category = None if not is_spam: categories = ["inquiry", "complaint", "thank you", "request", "information"] for category in categories: if category in response_text: email_category = category break # Update messages for tracking new_messages = state.get("messages", []) + [ {"role": "user", "content": prompt}, {"role": "assistant", "content": response.content} ] # Return state updates return { "is_spam": is_spam, "spam_reason": spam_reason, "email_category": email_category, "messages": new_messages } def handle_spam(state: EmailState): """Alfred discards spam email with a note""" print(f"Alfred has marked the email as spam. Reason: {state['spam_reason']}") print("The email has been moved to the spam folder.") # We're done processing this email return {} def draft_response(state: EmailState): """Alfred drafts a preliminary response for legitimate emails""" email = state["email"] category = state["email_category"] or "general" # Prepare our prompt for the LLM prompt = f""" As Alfred the butler, draft a polite preliminary response to this email. Email: From: {email['sender']} Subject: {email['subject']} Body: {email['body']} This email has been categorized as: {category} Draft a brief, professional response that Mr. Hugg can review and personalize before sending. """ # Call the LLM messages = [HumanMessage(content=prompt)] response = model.invoke(messages) # Update messages for tracking new_messages = state.get("messages", []) + [ {"role": "user", "content": prompt}, {"role": "assistant", "content": response.content} ] # Return state updates return { "email_draft": response.content, "messages": new_messages } def notify_mr_hugg(state: EmailState): """Alfred notifies Mr. Hugg about the email and presents the draft response""" email = state["email"] print("\n" + "="*50) print(f"Sir, you've received an email from {email['sender']}.") print(f"Subject: {email['subject']}") print(f"Category: {state['email_category']}") print("\nI've prepared a draft response for your review:") print("-"*50) print(state["email_draft"]) print("="*50 + "\n") # We're done processing this email return {} ``` ## Step 3: Define Our Routing Logic We need a function to determine which path to take after classification: ```python def route_email(state: EmailState) -> str: """Determine the next step based on spam classification""" if state["is_spam"]: return "spam" else: return "legitimate" ``` > 💡 **Note:** This routing function is called by LangGraph to determine which edge to follow after the classification node. The return value must match one of the keys in our conditional edges mapping. ## Step 4: Create the StateGraph and Define Edges Now we connect everything together: ```python # Create the graph email_graph = StateGraph(EmailState) # Add nodes email_graph.add_node("read_email", read_email) email_graph.add_node("classify_email", classify_email) email_graph.add_node("handle_spam", handle_spam) email_graph.add_node("draft_response", draft_response) email_graph.add_node("notify_mr_hugg", notify_mr_hugg) # Start the edges email_graph.add_edge(START, "read_email") # Add edges - defining the flow email_graph.add_edge("read_email", "classify_email") # Add conditional branching from classify_email email_graph.add_conditional_edges( "classify_email", route_email, { "spam": "handle_spam", "legitimate": "draft_response" } ) # Add the final edges email_graph.add_edge("handle_spam", END) email_graph.add_edge("draft_response", "notify_mr_hugg") email_graph.add_edge("notify_mr_hugg", END) # Compile the graph compiled_graph = email_graph.compile() ``` Notice how we use the special `END` node provided by LangGraph. This indicates terminal states where the workflow completes. ## Step 5: Run the Application Let's test our graph with a legitimate email and a spam email: ```python # Example legitimate email legitimate_email = { "sender": "john.smith@example.com", "subject": "Question about your services", "body": "Dear Mr. Hugg, I was referred to you by a colleague and I'm interested in learning more about your consulting services. Could we schedule a call next week? Best regards, John Smith" } # Example spam email spam_email = { "sender": "winner@lottery-intl.com", "subject": "YOU HAVE WON $5,000,000!!!", "body": "CONGRATULATIONS! You have been selected as the winner of our international lottery! To claim your $5,000,000 prize, please send us your bank details and a processing fee of $100." } # Process the legitimate email print("\nProcessing legitimate email...") legitimate_result = compiled_graph.invoke({ "email": legitimate_email, "is_spam": None, "spam_reason": None, "email_category": None, "email_draft": None, "messages": [] }) # Process the spam email print("\nProcessing spam email...") spam_result = compiled_graph.invoke({ "email": spam_email, "is_spam": None, "spam_reason": None, "email_category": None, "email_draft": None, "messages": [] }) ``` ## Step 6: Inspecting Our Mail Sorting Agent with Langfuse 📡 As Alfred fine-tunes the Mail Sorting Agent, he's growing weary of debugging its runs. Agents, by nature, are unpredictable and difficult to inspect. But since he aims to build the ultimate Spam Detection Agent and deploy it in production, he needs robust traceability for future monitoring and analysis. To do this, Alfred can use an observability tool such as [Langfuse](https://langfuse.com/) to trace and monitor the agent. First, we pip install Langfuse: ```python %pip install -q langfuse ``` Second, we pip install Langchain (LangChain is required because we use LangFuse): ```python %pip install langchain ``` Next, we add the Langfuse API keys and host address as environment variables. You can get your Langfuse credentials by signing up for [Langfuse Cloud](https://cloud.langfuse.com) or [self-host Langfuse](https://langfuse.com/self-hosting). ```python import os # Get keys for your project from the project settings page: https://cloud.langfuse.com os.environ["LANGFUSE_PUBLIC_KEY"] = "pk-lf-..." os.environ["LANGFUSE_SECRET_KEY"] = "sk-lf-..." os.environ["LANGFUSE_HOST"] = "https://cloud.langfuse.com" # 🇪🇺 EU region # os.environ["LANGFUSE_HOST"] = "https://us.cloud.langfuse.com" # 🇺🇸 US region ``` Then, we configure the [Langfuse `callback_handler`](https://langfuse.com/docs/integrations/langchain/tracing#add-langfuse-to-your-langchain-application) and instrument the agent by adding the `langfuse_callback` to the invocation of the graph: `config={"callbacks": [langfuse_handler]}`. ```python from langfuse.langchain import CallbackHandler # Initialize Langfuse CallbackHandler for LangGraph/Langchain (tracing) langfuse_handler = CallbackHandler() # Process legitimate email legitimate_result = compiled_graph.invoke( input={"email": legitimate_email, "is_spam": None, "spam_reason": None, "email_category": None, "draft_response": None, "messages": []}, config={"callbacks": [langfuse_handler]} ) ``` Alfred is now connected 🔌! The runs from LangGraph are being logged in Langfuse, giving him full visibility into the agent's behavior. With this setup, he's ready to revisit previous runs and refine his Mail Sorting Agent even further. ![Example trace in Langfuse](https://langfuse.com/images/cookbook/huggingface-agent-course/langgraph-trace-legit.png) _[Public link to the trace with the legit email](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/f5d6d72e-20af-4357-b232-af44c3728a7b?timestamp=2025-03-17T10%3A13%3A28.413Z&observation=6997ba69-043f-4f77-9445-700a033afba1)_ ## Visualizing Our Graph LangGraph allows us to visualize our workflow to better understand and debug its structure: ```python compiled_graph.get_graph().draw_mermaid_png() ``` Mail LangGraph This produces a visual representation showing how our nodes are connected and the conditional paths that can be taken. ## What We've Built We've created a complete email processing workflow that: 1. Takes an incoming email 2. Uses an LLM to classify it as spam or legitimate 3. Handles spam by discarding it 4. For legitimate emails, drafts a response and notifies Mr. Hugg This demonstrates the power of LangGraph to orchestrate complex workflows with LLMs while maintaining a clear, structured flow. ## Key Takeaways - **State Management**: We defined comprehensive state to track all aspects of email processing - **Node Implementation**: We created functional nodes that interact with an LLM - **Conditional Routing**: We implemented branching logic based on email classification - **Terminal States**: We used the END node to mark completion points in our workflow ## What's Next? In the next section, we'll explore more advanced features of LangGraph, including handling human interaction in the workflow and implementing more complex branching logic based on multiple conditions. ================================================ FILE: units/en/unit2/langgraph/introduction.mdx ================================================ # Introduction to `LangGraph` Unit 2.3 Thumbnail Welcome to this next part of our journey, where you'll learn **how to build applications** using the [`LangGraph`](https://github.com/langchain-ai/langgraph) framework designed to help you structure and orchestrate complex LLM workflows. `LangGraph` is a framework that allows you to build **production-ready** applications by giving you **control** tools over the flow of your agent. ## Module Overview In this unit, you'll discover: ### 1️⃣ [What is LangGraph, and when to use it?](./when_to_use_langgraph) ### 2️⃣ [Building Blocks of LangGraph](./building_blocks) ### 3️⃣ [Alfred, the mail sorting butler](./first_graph) ### 4️⃣ [Alfred, the document Analyst agent](./document_analysis_agent) ### 5️⃣ [Quiz](./quizz1) > [!WARNING] > The examples in this section require access to a powerful LLM/VLM model. We ran them using the GPT-4o API because it has the best compatibility with LangGraph. By the end of this unit, you'll be equipped to build robust, organized and production ready applications ! That being said, this section is an introduction to LangGraph and more advanced topics can be discovered in the free LangChain academy course : [Introduction to LangGraph](https://academy.langchain.com/courses/intro-to-langgraph) Let's get started! ## Resources - [LangGraph Agents](https://langchain-ai.github.io/langgraph/) - Examples of LangGraph agent - [LangChain academy](https://academy.langchain.com/courses/intro-to-langgraph) - Full course on LangGraph from LangChain ================================================ FILE: units/en/unit2/langgraph/quiz1.mdx ================================================ # Test Your Understanding of LangGraph Let's test your understanding of `LangGraph` with a quick quiz! This will help reinforce the key concepts we've covered so far. This is an optional quiz and it's not graded. ### Q1: What is the primary purpose of LangGraph? Which statement best describes what LangGraph is designed for? --- ### Q2: In the context of the "Control vs Freedom" trade-off, where does LangGraph stand? Which statement best characterizes LangGraph's approach to agent design? --- ### Q3: What role does State play in LangGraph? Choose the most accurate description of State in LangGraph. ### Q4: What is a Conditional Edge in LangGraph? Select the most accurate description. --- ### Q5: How does LangGraph help address the hallucination problem in LLMs? Choose the best answer. Congratulations on completing the quiz! 🎉 If you missed any questions, consider reviewing the previous sections to strengthen your understanding. Next, we'll explore more advanced features of LangGraph and see how to build more complex agent workflows. ================================================ FILE: units/en/unit2/langgraph/when_to_use_langgraph.mdx ================================================ # What is `LangGraph`? [[what-is-langgraph]] `LangGraph` is a framework developed by [LangChain](https://www.langchain.com/) **to manage the control flow of applications that integrate an LLM**. ## Is `LangGraph` different from `LangChain`? LangChain provides a standard interface to interact with models and other components, useful for retrieval, LLM calls and tools calls. The classes from LangChain might be used in LangGraph, but do not HAVE to be used. The packages are different and can be used in isolation, but, in the end, all resources you will find online use both packages hand in hand. ## When should I use `LangGraph`? ### Control vs freedom When designing AI applications, you face a fundamental trade-off between **control** and **freedom**: - **Freedom** gives your LLM more room to be creative and tackle unexpected problems. - **Control** allows you to ensure predictable behavior and maintain guardrails. Code Agents, like the ones you can encounter in *smolagents*, are very free. They can call multiple tools in a single action step, create their own tools, etc. However, this behavior can make them less predictable and less controllable than a regular Agent working with JSON! `LangGraph` is on the other end of the spectrum, it shines when you need **"Control"** on the execution of your agent. LangGraph is particularly valuable when you need **Control over your applications**. It gives you the tools to build an application that follows a predictable process while still leveraging the power of LLMs. Put simply, if your application involves a series of steps that need to be orchestrated in a specific way, with decisions being made at each junction point, **LangGraph provides the structure you need**. As an example, let's say we want to build an LLM assistant that can answer some questions over some documents. Since LLMs understand text the best, before being able to answer the question, you will need to convert other complex modalities (charts, tables) into text. However, that choice depends on the type of document you have! This is a branching that I chose to represent as follow : Control flow > 💡 **Tip:** The left part is not an agent, as here no tool call is involved. but the right part will need to write some code to query the xls ( convert to pandas and manipulate it ). While this branching is deterministic, you can also design branching that are conditioned on the output of an LLM making them undeterministic. The key scenarios where LangGraph excels include: - **Multi-step reasoning processes** that need explicit control on the flow - **Applications requiring persistence of state** between steps - **Systems that combine deterministic logic with AI capabilities** - **Workflows that need human-in-the-loop interventions** - **Complex agent architectures** with multiple components working together In essence, whenever possible, **as a human**, design a flow of actions based on the output of each action, and decide what to execute next accordingly. In this case, LangGraph is the correct framework for you! `LangGraph` is, in my opinion, the most production-ready agent framework on the market. ## How does LangGraph work? At its core, `LangGraph` uses a directed graph structure to define the flow of your application: - **Nodes** represent individual processing steps (like calling an LLM, using a tool, or making a decision). - **Edges** define the possible transitions between steps. - **State** is user defined and maintained and passed between nodes during execution. When deciding which node to target next, this is the current state that we look at. We will explore those fundamental blocks more in the next chapter! ## How is it different from regular python? Why do I need LangGraph? You might wonder: "I could just write regular Python code with if-else statements to handle all these flows, right?" While technically true, LangGraph offers **some advantages** over vanilla Python for building complex systems. You could build the same application without LangGraph, but it builds easier tools and abstractions for you. It includes states, visualization, logging (traces), built-in human-in-the-loop, and more. ================================================ FILE: units/en/unit2/llama-index/README.md ================================================ # Table of Contents This LlamaIndex frame outline is part of unit 2 of the course. You can access the unit 2 about LlamaIndex on hf.co/learn 👉 here | Title | Description | | --- | --- | | [Introduction](introduction.mdx) | Introduction to LlamaIndex | | [LlamaHub](llama-hub.mdx) | LlamaHub: a registry of integrations, agents and tools | | [Components](components.mdx) | Components: the building blocks of workflows | | [Tools](tools.mdx) | Tools: how to build tools in LlamaIndex | | [Quiz 1](quiz1.mdx) | Quiz 1 | | [Agents](agents.mdx) | Agents: how to build agents in LlamaIndex | | [Workflows](workflows.mdx) | Workflows: a sequence of steps, events made of components that are executed in order | | [Quiz 2](quiz2.mdx) | Quiz 2 | | [Conclusion](conclusion.mdx) | Conclusion | ================================================ FILE: units/en/unit2/llama-index/agents.mdx ================================================ # Using Agents in LlamaIndex Remember Alfred, our helpful butler agent from earlier? Well, he's about to get an upgrade! Now that we understand the tools available in LlamaIndex, we can give Alfred new capabilities to serve us better. But before we continue, let's remind ourselves what makes an agent like Alfred tick. Back in Unit 1, we learned that: > An Agent is a system that leverages an AI model to interact with its environment to achieve a user-defined objective. It combines reasoning, planning, and action execution (often via external tools) to fulfil tasks. LlamaIndex supports **three main types of reasoning agents:** ![Agents](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/agents.png) 1. `Function Calling Agents` - These work with AI models that can call specific functions. 2. `ReAct Agents` - These can work with any AI that does chat or text endpoint and deal with complex reasoning tasks. 3. `Advanced Custom Agents` - These use more complex methods to deal with more complex tasks and workflows. > [!TIP] > Find more information on advanced agents on BaseWorkflowAgent ## Initialising Agents > [!TIP] > You can follow the code in this notebook that you can run using Google Colab. To create an agent, we start by providing it with a **set of functions/tools that define its capabilities**. Let's look at how to create an agent with some basic tools. As of this writing, the agent will automatically use the function calling API (if available), or a standard ReAct agent loop. LLMs that support a tools/functions API are relatively new, but they provide a powerful way to call tools by avoiding specific prompting and allowing the LLM to create tool calls based on provided schemas. ReAct agents are also good at complex reasoning tasks and can work with any LLM that has chat or text completion capabilities. They are more verbose, and show the reasoning behind certain actions that they take. ```python from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI from llama_index.core.agent.workflow import AgentWorkflow from llama_index.core.tools import FunctionTool # define sample Tool -- type annotations, function names, and docstrings, are all included in parsed schemas! def multiply(a: int, b: int) -> int: """Multiplies two integers and returns the resulting integer""" return a * b # initialize llm llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") # initialize agent agent = AgentWorkflow.from_tools_or_functions( [FunctionTool.from_defaults(multiply)], llm=llm ) ``` **Agents are stateless by default**, however, they can remember past interactions using a `Context` object. This might be useful if you want to use an agent that needs to remember previous interactions, like a chatbot that maintains context across multiple messages or a task manager that needs to track progress over time. ```python # stateless response = await agent.run("What is 2 times 2?") # remembering state from llama_index.core.workflow import Context ctx = Context(agent) response = await agent.run("My name is Bob.", ctx=ctx) response = await agent.run("What was my name again?", ctx=ctx) ``` You'll notice that agents in `LlamaIndex` are async because they use Python's `await` operator. If you are new to async code in Python, or need a refresher, they have an [excellent async guide](https://docs.llamaindex.ai/en/stable/getting_started/async_python/). Now we've gotten the basics, let's take a look at how we can use more complex tools in our agents. ## Creating RAG Agents with QueryEngineTools **Agentic RAG is a powerful way to use agents to answer questions about your data.** We can pass various tools to Alfred to help him answer questions. However, instead of answering the question on top of documents automatically, Alfred can decide to use any other tool or flow to answer the question. ![Agentic RAG](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/agentic-rag.png) It is easy to **wrap `QueryEngine` as a tool** for an agent. When doing so, we need to **define a name and description**. The LLM will use this information to correctly use the tool. Let's see how to load in a `QueryEngineTool` using the `QueryEngine` we created in the [component section](components). ```python from llama_index.core.tools import QueryEngineTool query_engine = index.as_query_engine(llm=llm, similarity_top_k=3) # as shown in the Components in LlamaIndex section query_engine_tool = QueryEngineTool.from_defaults( query_engine=query_engine, name="name", description="a specific description", return_direct=False, ) query_engine_agent = AgentWorkflow.from_tools_or_functions( [query_engine_tool], llm=llm, system_prompt="You are a helpful assistant that has access to a database containing persona descriptions. " ) ``` ## Creating Multi-agent systems The `AgentWorkflow` class also directly supports multi-agent systems. By giving each agent a name and description, the system maintains a single active speaker, with each agent having the ability to hand off to another agent. By narrowing the scope of each agent, we can help increase their general accuracy when responding to user messages. **Agents in LlamaIndex can also directly be used as tools** for other agents, for more complex and custom scenarios. ```python from llama_index.core.agent.workflow import ( AgentWorkflow, FunctionAgent, ReActAgent, ) # Define some tools def add(a: int, b: int) -> int: """Add two numbers.""" return a + b def subtract(a: int, b: int) -> int: """Subtract two numbers.""" return a - b # Create agent configs # NOTE: we can use FunctionAgent or ReActAgent here. # FunctionAgent works for LLMs with a function calling API. # ReActAgent works for any LLM. calculator_agent = ReActAgent( name="calculator", description="Performs basic arithmetic operations", system_prompt="You are a calculator assistant. Use your tools for any math operation.", tools=[add, subtract], llm=llm, ) query_agent = ReActAgent( name="info_lookup", description="Looks up information about XYZ", system_prompt="Use your tool to query a RAG system to answer information about XYZ", tools=[query_engine_tool], llm=llm ) # Create and run the workflow agent = AgentWorkflow( agents=[calculator_agent, query_agent], root_agent="calculator" ) # Run the system response = await agent.run(user_msg="Can you add 5 and 3?") ``` > [!TIP] > Haven't learned enough yet? There is a lot more to discover about agents and tools in LlamaIndex within the AgentWorkflow Basic Introduction or the Agent Learning Guide, where you can read more about streaming, context serialization, and human-in-the-loop! Now that we understand the basics of agents and tools in LlamaIndex, let's see how we can use LlamaIndex to **create configurable and manageable workflows!** ================================================ FILE: units/en/unit2/llama-index/components.mdx ================================================ # What are components in LlamaIndex? Remember Alfred, our helpful butler agent from Unit 1? To assist us effectively, Alfred needs to understand our requests and **prepare, find and use relevant information to help complete tasks.** This is where LlamaIndex's components come in. While LlamaIndex has many components, **we'll focus specifically on the `QueryEngine` component.** Why? Because it can be used as a Retrieval-Augmented Generation (RAG) tool for an agent. So, what is RAG? LLMs are trained on enormous bodies of data to learn general knowledge. However, they may not be trained on relevant and up-to-date data. RAG solves this problem by finding and retrieving relevant information from your data and giving that to the LLM. ![RAG](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/rag.png) Now, think about how Alfred works: 1. You ask Alfred to help plan a dinner party 2. Alfred needs to check your calendar, dietary preferences, and past successful menus 3. The `QueryEngine` helps Alfred find this information and use it to plan the dinner party This makes the `QueryEngine` **a key component for building agentic RAG workflows** in LlamaIndex. Just as Alfred needs to search through your household information to be helpful, any agent needs a way to find and understand relevant data. The `QueryEngine` provides exactly this capability. Now, let's dive a bit deeper into the components and see how you can **combine components to create a RAG pipeline.** ## Creating a RAG pipeline using components > [!TIP] > You can follow the code in this notebook that you can run using Google Colab. There are five key stages within RAG, which in turn will be a part of most larger applications you build. These are: 1. **Loading**: this refers to getting your data from where it lives -- whether it's text files, PDFs, another website, a database, or an API -- into your workflow. LlamaHub provides hundreds of integrations to choose from. 2. **Indexing**: this means creating a data structure that allows for querying the data. For LLMs, this nearly always means creating vector embeddings. Which are numerical representations of the meaning of the data. Indexing can also refer to numerous other metadata strategies to make it easy to accurately find contextually relevant data based on properties. 3. **Storing**: once your data is indexed you will want to store your index, as well as other metadata, to avoid having to re-index it. 4. **Querying**: for any given indexing strategy there are many ways you can utilize LLMs and LlamaIndex data structures to query, including sub-queries, multi-step queries and hybrid strategies. 5. **Evaluation**: a critical step in any flow is checking how effective it is relative to other strategies, or when you make changes. Evaluation provides objective measures of how accurate, faithful and fast your responses to queries are. Next, let's see how we can reproduce these stages using components. ### Loading and embedding documents As mentioned before, LlamaIndex can work on top of your own data, however, **before accessing data, we need to load it.** There are three main ways to load data into LlamaIndex: 1. `SimpleDirectoryReader`: A built-in loader for various file types from a local directory. 2. `LlamaParse`: LlamaParse, LlamaIndex's official tool for PDF parsing, available as a managed API. 3. `LlamaHub`: A registry of hundreds of data-loading libraries to ingest data from any source. > [!TIP] > Get familiar with LlamaHub loaders and LlamaParse parser for more complex data sources. **The simplest way to load data is with `SimpleDirectoryReader`.** This versatile component can load various file types from a folder and convert them into `Document` objects that LlamaIndex can work with. Let's see how we can use `SimpleDirectoryReader` to load data from a folder. ```python from llama_index.core import SimpleDirectoryReader reader = SimpleDirectoryReader(input_dir="path/to/directory") documents = reader.load_data() ``` After loading our documents, we need to break them into smaller pieces called `Node` objects. A `Node` is just a chunk of text from the original document that's easier for the AI to work with, while it still has references to the original `Document` object. The `IngestionPipeline` helps us create these nodes through two key transformations. 1. `SentenceSplitter` breaks down documents into manageable chunks by splitting them at natural sentence boundaries. 2. `HuggingFaceEmbedding` converts each chunk into numerical embeddings - vector representations that capture the semantic meaning in a way AI can process efficiently. This process helps us organise our documents in a way that's more useful for searching and analysis. ```python from llama_index.core import Document from llama_index.embeddings.huggingface import HuggingFaceEmbedding from llama_index.core.node_parser import SentenceSplitter from llama_index.core.ingestion import IngestionPipeline # create the pipeline with transformations pipeline = IngestionPipeline( transformations=[ SentenceSplitter(chunk_overlap=0), HuggingFaceEmbedding(model_name="BAAI/bge-small-en-v1.5"), ] ) nodes = await pipeline.arun(documents=[Document.example()]) ``` ### Storing and indexing documents After creating our `Node` objects we need to index them to make them searchable, but before we can do that, we need a place to store our data. Since we are using an ingestion pipeline, we can directly attach a vector store to the pipeline to populate it. In this case, we will use `Chroma` to store our documents.
Install ChromaDB As introduced in the section on the LlamaHub, we can install the ChromaDB vector store with the following command: ```bash pip install llama-index-vector-stores-chroma ```
```python import chromadb from llama_index.vector_stores.chroma import ChromaVectorStore db = chromadb.PersistentClient(path="./alfred_chroma_db") chroma_collection = db.get_or_create_collection("alfred") vector_store = ChromaVectorStore(chroma_collection=chroma_collection) pipeline = IngestionPipeline( transformations=[ SentenceSplitter(chunk_size=25, chunk_overlap=0), HuggingFaceEmbedding(model_name="BAAI/bge-small-en-v1.5"), ], vector_store=vector_store, ) ``` > [!TIP] > An overview of the different vector stores can be found in the LlamaIndex documentation. This is where vector embeddings come in - by embedding both the query and nodes in the same vector space, we can find relevant matches. The `VectorStoreIndex` handles this for us, using the same embedding model we used during ingestion to ensure consistency. Let's see how to create this index from our vector store and embeddings: ```python from llama_index.core import VectorStoreIndex from llama_index.embeddings.huggingface import HuggingFaceEmbedding embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-small-en-v1.5") index = VectorStoreIndex.from_vector_store(vector_store, embed_model=embed_model) ``` All information is automatically persisted within the `ChromaVectorStore` object and the passed directory path. Great! Now that we can save and load our index easily, let's explore how to query it in different ways. ### Querying a VectorStoreIndex with prompts and LLMs Before we can query our index, we need to convert it to a query interface. The most common conversion options are: - `as_retriever`: For basic document retrieval, returning a list of `NodeWithScore` objects with similarity scores - `as_query_engine`: For single question-answer interactions, returning a written response - `as_chat_engine`: For conversational interactions that maintain memory across multiple messages, returning a written response using chat history and indexed context We'll focus on the query engine since it is more common for agent-like interactions. We also pass in an LLM to the query engine to use for the response. ```python from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") query_engine = index.as_query_engine( llm=llm, response_mode="tree_summarize", ) query_engine.query("What is the meaning of life?") # The meaning of life is 42 ``` ### Response Processing Under the hood, the query engine doesn't only use the LLM to answer the question but also uses a `ResponseSynthesizer` as a strategy to process the response. Once again, this is fully customisable but there are three main strategies that work well out of the box: - `refine`: create and refine an answer by sequentially going through each retrieved text chunk. This makes a separate LLM call per Node/retrieved chunk. - `compact` (default): similar to refining but concatenating the chunks beforehand, resulting in fewer LLM calls. - `tree_summarize`: create a detailed answer by going through each retrieved text chunk and creating a tree structure of the answer. > [!TIP] > Take fine-grained control of your query workflows with the low-level composition API. This API lets you customize and fine-tune every step of the query process to match your exact needs, which also pairs great with Workflows The language model won't always perform in predictable ways, so we can't be sure that the answer we get is always correct. We can deal with this by **evaluating the quality of the answer**. ### Evaluation and observability LlamaIndex provides **built-in evaluation tools to assess response quality.** These evaluators leverage LLMs to analyze responses across different dimensions. Let's look at the three main evaluators available: - `FaithfulnessEvaluator`: Evaluates the faithfulness of the answer by checking if the answer is supported by the context. - `AnswerRelevancyEvaluator`: Evaluate the relevance of the answer by checking if the answer is relevant to the question. - `CorrectnessEvaluator`: Evaluate the correctness of the answer by checking if the answer is correct. > [!TIP] > Want to learn more about agent observability and evaluation? Continue your journey with the Bonus Unit 2. ```python from llama_index.core.evaluation import FaithfulnessEvaluator query_engine = # from the previous section llm = # from the previous section # query index evaluator = FaithfulnessEvaluator(llm=llm) response = query_engine.query( "What battles took place in New York City in the American Revolution?" ) eval_result = evaluator.evaluate_response(response=response) eval_result.passing ``` Even without direct evaluation, we can **gain insights into how our system is performing through observability.** This is especially useful when we are building more complex workflows and want to understand how each component is performing.
Install LlamaTrace As introduced in the section on the LlamaHub, we can install the LlamaTrace callback from Arize Phoenix with the following command: ```bash pip install -U llama-index-callbacks-arize-phoenix ``` Additionally, we need to set the `PHOENIX_API_KEY` environment variable to our LlamaTrace API key. We can get this by: - Creating an account at [LlamaTrace](https://llamatrace.com/login) - Generating an API key in your account settings - Using the API key in the code below to enable tracing
```python import llama_index import os PHOENIX_API_KEY = "" os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = f"api_key={PHOENIX_API_KEY}" llama_index.core.set_global_handler( "arize_phoenix", endpoint="https://llamatrace.com/v1/traces" ) ``` > [!TIP] > Want to learn more about components and how to use them? Continue your journey with the Components Guides or the Guide on RAG. We have seen how to use components to create a `QueryEngine`. Now, let's see how we can **use the `QueryEngine` as a tool for an agent!** ================================================ FILE: units/en/unit2/llama-index/conclusion.mdx ================================================ # Conclusion Congratulations on finishing the `llama-index` module of this second Unit 🥳 You’ve just mastered the fundamentals of `llama-index` and you’ve seen how to build your own agentic workflows! Now that you have skills in `llama-index`, you can start to create search engines that will solve tasks you're interested in. In the next module of the unit, you're going to learn **how to build Agents with LangGraph**. Finally, we would love **to hear what you think of the course and how we can improve it**. If you have some feedback then, please 👉 [fill this form](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ### Keep Learning, and stay awesome 🤗 ================================================ FILE: units/en/unit2/llama-index/introduction.mdx ================================================ # Introduction to LlamaIndex Welcome to this module, where you’ll learn how to build LLM-powered agents using the [LlamaIndex](https://www.llamaindex.ai/) toolkit. LlamaIndex is **a complete toolkit for creating LLM-powered agents over your data using indexes and workflows**. For this course we'll focus on three main parts that help build agents in LlamaIndex: **Components**, **Agents and Tools** and **Workflows**. ![LlamaIndex](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/thumbnail.png) Let's look at these key parts of LlamaIndex and how they help with agents: - **Components**: Are the basic building blocks you use in LlamaIndex. These include things like prompts, models, and databases. Components often help connect LlamaIndex with other tools and libraries. - **Tools**: Tools are components that provide specific capabilities like searching, calculating, or accessing external services. They are the building blocks that enable agents to perform tasks. - **Agents**: Agents are autonomous components that can use tools and make decisions. They coordinate tool usage to accomplish complex goals. - **Workflows**: Are step-by-step processes that process logic together. Workflows or agentic workflows are a way to structure agentic behaviour without the explicit use of agents. ## What Makes LlamaIndex Special? While LlamaIndex does some things similar to other frameworks like smolagents, it has some key benefits: - **Clear Workflow System**: Workflows help break down how agents should make decisions step by step using an event-driven and async-first syntax. This helps you clearly compose and organize your logic. - **Advanced Document Parsing with LlamaParse**: LlamaParse was made specifically for LlamaIndex, so the integration is seamless, although it is a paid feature. - **Many Ready-to-Use Components**: LlamaIndex has been around for a while, so it works with lots of other frameworks. This means it has many tested and reliable components, like LLMs, retrievers, indexes, and more. - **LlamaHub**: is a registry of hundreds of these components, agents, and tools that you can use within LlamaIndex. All of these concepts are required in different scenarios to create useful agents. In the following sections, we will go over each of these concepts in detail. After mastering the concepts, we will use our learnings to **create applied use cases with Alfred the agent**! Getting our hands on LlamaIndex is exciting, right? So, what are we waiting for? Let's get started with **finding and installing the integrations we need using LlamaHub! 🚀** ================================================ FILE: units/en/unit2/llama-index/llama-hub.mdx ================================================ # Introduction to the LlamaHub **LlamaHub is a registry of hundreds of integrations, agents and tools that you can use within LlamaIndex.** ![LlamaHub](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/llama-hub.png) We will be using various integrations in this course, so let's first look at the LlamaHub and how it can help us. Let's see how to find and install the dependencies for the components we need. ## Installation LlamaIndex installation instructions are available as a well-structured **overview on [LlamaHub](https://llamahub.ai/)**. This might be a bit overwhelming at first, but most of the **installation commands generally follow an easy-to-remember format**: ```bash pip install llama-index-{component-type}-{framework-name} ``` Let's try to install the dependencies for an LLM and embedding component using the [Hugging Face inference API integration](https://llamahub.ai/l/llms/llama-index-llms-huggingface-api?from=llms). ```bash pip install llama-index-llms-huggingface-api llama-index-embeddings-huggingface ``` ## Usage Once installed, we can see the usage patterns. You'll notice that the import paths follow the install command! Underneath, we can see an example of the usage of **the Hugging Face inference API for an LLM component**. ```python from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI import os from dotenv import load_dotenv # Load the .env file load_dotenv() # Retrieve HF_TOKEN from the environment variables hf_token = os.getenv("HF_TOKEN") llm = HuggingFaceInferenceAPI( model_name="Qwen/Qwen2.5-Coder-32B-Instruct", temperature=0.7, max_tokens=100, token=hf_token, provider="auto" ) response = llm.complete("Hello, how are you?") print(response) # I am good, how can I help you today? ``` Wonderful, we now know how to find, install and use the integrations for the components we need. **Let's dive deeper into the components** and see how we can use them to build our own agents. ================================================ FILE: units/en/unit2/llama-index/quiz1.mdx ================================================ # Small Quiz (ungraded) [[quiz1]] So far we've discussed the key components and tools used in LlamaIndex. It's time to make a short quiz, since **testing yourself** is the best way to learn and [to avoid the illusion of competence](https://www.coursera.org/lecture/learning-how-to-learn/illusions-of-competence-BuFzf). This will help you find **where you need to reinforce your knowledge**. This is an optional quiz and it's not graded. ### Q1: What is a QueryEngine? Which of the following best describes a QueryEngine component? --- ### Q2: What is the Purpose of FunctionTools? Why are FunctionTools important for an Agent? --- ### Q3: What are Toolspecs in LlamaIndex? What is the main purpose of Toolspecs? --- ### Q4: What is Required to create a tool? What information must be included when creating a tool? --- Congrats on finishing this Quiz 🥳, if you missed some elements, take time to read again the chapter to reinforce your knowledge. If you pass it, you're ready to dive deeper into building with these components! ================================================ FILE: units/en/unit2/llama-index/quiz2.mdx ================================================ # Quick Self-Check (ungraded) [[quiz2]] What?! Another Quiz? We know, we know, ... 😅 But this short, ungraded quiz is here to **help you reinforce key concepts you've just learned**. This quiz covers agent workflows and interactions - essential components for building effective AI agents. ### Q1: What is the purpose of AgentWorkflow in LlamaIndex? --- ### Q2: What object is used for keeping track of the state of the workflow? --- ### Q3: Which method should be used if you want an agent to remember previous interactions? --- ### Q4: What is a key feature of Agentic RAG? --- Got it? Great! Now let's **do a brief recap of the unit!** ================================================ FILE: units/en/unit2/llama-index/tools.mdx ================================================ # Using Tools in LlamaIndex **Defining a clear set of Tools is crucial to performance.** As we discussed in [unit 1](../../unit1/tools), clear tool interfaces are easier for LLMs to use. Much like a software API interface for human engineers, they can get more out of the tool if it's easy to understand how it works. There are **four main types of tools in LlamaIndex**: ![Tools](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/tools.png) 1. `FunctionTool`: Convert any Python function into a tool that an agent can use. It automatically figures out how the function works. 2. `QueryEngineTool`: A tool that lets agents use query engines. Since agents are built on query engines, they can also use other agents as tools. 3. `Toolspecs`: Sets of tools created by the community, which often include tools for specific services like Gmail. 4. `Utility Tools`: Special tools that help handle large amounts of data from other tools. We will go over each of them in more detail below. ## Creating a FunctionTool > [!TIP] > You can follow the code in this notebook that you can run using Google Colab. A FunctionTool provides a simple way to wrap any Python function and make it available to an agent. You can pass either a synchronous or asynchronous function to the tool, along with optional `name` and `description` parameters. The name and description are particularly important as they help the agent understand when and how to use the tool effectively. Let's look at how to create a FunctionTool below and then call it. ```python from llama_index.core.tools import FunctionTool def get_weather(location: str) -> str: """Useful for getting the weather for a given location.""" print(f"Getting weather for {location}") return f"The weather in {location} is sunny" tool = FunctionTool.from_defaults( get_weather, name="my_weather_tool", description="Useful for getting the weather for a given location.", ) tool.call("New York") ``` > [!TIP] > When using an agent or LLM with function calling, the tool selected (and the arguments written for that tool) rely strongly on the tool name and description of the purpose and arguments of the tool. Learn more about function calling in the Function Calling Guide. ## Creating a QueryEngineTool The `QueryEngine` we defined in the previous unit can be easily transformed into a tool using the `QueryEngineTool` class. Let's see how to create a `QueryEngineTool` from a `QueryEngine` in the example below. ```python from llama_index.core import VectorStoreIndex from llama_index.core.tools import QueryEngineTool from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI from llama_index.embeddings.huggingface import HuggingFaceEmbedding from llama_index.vector_stores.chroma import ChromaVectorStore embed_model = HuggingFaceEmbedding("BAAI/bge-small-en-v1.5") db = chromadb.PersistentClient(path="./alfred_chroma_db") chroma_collection = db.get_or_create_collection("alfred") vector_store = ChromaVectorStore(chroma_collection=chroma_collection) index = VectorStoreIndex.from_vector_store(vector_store, embed_model=embed_model) llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") query_engine = index.as_query_engine(llm=llm) tool = QueryEngineTool.from_defaults(query_engine, name="some useful name", description="some useful description") ``` ## Creating Toolspecs Think of `ToolSpecs` as collections of tools that work together harmoniously - like a well-organized professional toolkit. Just as a mechanic's toolkit contains complementary tools that work together for vehicle repairs, a `ToolSpec` combines related tools for specific purposes. For example, an accounting agent's `ToolSpec` might elegantly integrate spreadsheet capabilities, email functionality, and calculation tools to handle financial tasks with precision and efficiency.
Install the Google Toolspec As introduced in the section on the LlamaHub, we can install the Google toolspec with the following command: ```python pip install llama-index-tools-google ```
And now we can load the toolspec and convert it to a list of tools. ```python from llama_index.tools.google import GmailToolSpec tool_spec = GmailToolSpec() tool_spec_list = tool_spec.to_tool_list() ``` To get a more detailed view of the tools, we can take a look at the `metadata` of each tool. ```python [(tool.metadata.name, tool.metadata.description) for tool in tool_spec_list] ``` ### Model Context Protocol (MCP) in LlamaIndex LlamaIndex also allows using MCP tools through a [ToolSpec on the LlamaHub](https://llamahub.ai/l/tools/llama-index-tools-mcp?from=). You can simply run an MCP server and start using it through the following implementation. If you want to dive deeper about MCP, you can check our [free MCP Course](https://huggingface.co/learn/mcp-course/).
Install the MCP Toolspec As introduced in the section on the LlamaHub, we can install the MCP toolspec with the following command: ```python pip install llama-index-tools-mcp ```
```python from llama_index.tools.mcp import BasicMCPClient, McpToolSpec # We consider there is a mcp server running on 127.0.0.1:8000, or you can use the mcp client to connect to your own mcp server. mcp_client = BasicMCPClient("http://127.0.0.1:8000/sse") mcp_tool = McpToolSpec(client=mcp_client) # get the agent agent = await get_agent(mcp_tool) # create the agent context agent_context = Context(agent) ``` ## Utility Tools Oftentimes, directly querying an API **can return an excessive amount of data**, some of which may be irrelevant, overflow the context window of the LLM, or unnecessarily increase the number of tokens that you are using. Let's walk through our two main utility tools below. 1. `OnDemandToolLoader`: This tool turns any existing LlamaIndex data loader (BaseReader class) into a tool that an agent can use. The tool can be called with all the parameters needed to trigger `load_data` from the data loader, along with a natural language query string. During execution, we first load data from the data loader, index it (for instance with a vector store), and then query it 'on-demand'. All three of these steps happen in a single tool call. 2. `LoadAndSearchToolSpec`: The LoadAndSearchToolSpec takes in any existing Tool as input. As a tool spec, it implements `to_tool_list`, and when that function is called, two tools are returned: a loading tool and then a search tool. The load Tool execution would call the underlying Tool, and then index the output (by default with a vector index). The search Tool execution would take in a query string as input and call the underlying index. > [!TIP] > You can find toolspecs and utility tools on the LlamaHub Now that we understand the basics of agents and tools in LlamaIndex, let's see how we can **use LlamaIndex to create configurable and manageable workflows!** ================================================ FILE: units/en/unit2/llama-index/workflows.mdx ================================================ # Creating agentic workflows in LlamaIndex A workflow in LlamaIndex provides a structured way to organize your code into sequential and manageable steps. Such a workflow is created by defining `Steps` which are triggered by `Events`, and themselves emit `Events` to trigger further steps. Let's take a look at Alfred showing a LlamaIndex workflow for a RAG task. ![Workflow Schematic](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/workflows.png) **Workflows offer several key benefits:** - Clear organization of code into discrete steps - Event-driven architecture for flexible control flow - Type-safe communication between steps - Built-in state management - Support for both simple and complex agent interactions As you might have guessed, **workflows strike a great balance between the autonomy of agents while maintaining control over the overall workflow.** So, let's learn how to create a workflow ourselves! ## Creating Workflows > [!TIP] > You can follow the code in this notebook that you can run using Google Colab. ### Basic Workflow Creation
Install the Workflow package As introduced in the section on the LlamaHub, we can install the Workflow package with the following command: ```python pip install llama-index-utils-workflow ```
We can create a single-step workflow by defining a class that inherits from `Workflow` and decorating your functions with `@step`. We will also need to add `StartEvent` and `StopEvent`, which are special events that are used to indicate the start and end of the workflow. ```python from llama_index.core.workflow import StartEvent, StopEvent, Workflow, step class MyWorkflow(Workflow): @step async def my_step(self, ev: StartEvent) -> StopEvent: # do something here return StopEvent(result="Hello, world!") w = MyWorkflow(timeout=10, verbose=False) result = await w.run() ``` As you can see, we can now run the workflow by calling `w.run()`. ### Connecting Multiple Steps To connect multiple steps, we **create custom events that carry data between steps.** To do so, we need to add an `Event` that is passed between the steps and transfers the output of the first step to the second step. ```python from llama_index.core.workflow import Event class ProcessingEvent(Event): intermediate_result: str class MultiStepWorkflow(Workflow): @step async def step_one(self, ev: StartEvent) -> ProcessingEvent: # Process initial data return ProcessingEvent(intermediate_result="Step 1 complete") @step async def step_two(self, ev: ProcessingEvent) -> StopEvent: # Use the intermediate result final_result = f"Finished processing: {ev.intermediate_result}" return StopEvent(result=final_result) w = MultiStepWorkflow(timeout=10, verbose=False) result = await w.run() result ``` The type hinting is important here, as it ensures that the workflow is executed correctly. Let's complicate things a bit more! ### Loops and Branches The type hinting is the most powerful part of workflows because it allows us to create branches, loops, and joins to facilitate more complex workflows. Let's show an example of **creating a loop** by using the union operator `|`. In the example below, we see that the `LoopEvent` is taken as input for the step and can also be returned as output. ```python from llama_index.core.workflow import Event import random class ProcessingEvent(Event): intermediate_result: str class LoopEvent(Event): loop_output: str class MultiStepWorkflow(Workflow): @step async def step_one(self, ev: StartEvent | LoopEvent) -> ProcessingEvent | LoopEvent: if random.randint(0, 1) == 0: print("Bad thing happened") return LoopEvent(loop_output="Back to step one.") else: print("Good thing happened") return ProcessingEvent(intermediate_result="First step complete.") @step async def step_two(self, ev: ProcessingEvent) -> StopEvent: # Use the intermediate result final_result = f"Finished processing: {ev.intermediate_result}" return StopEvent(result=final_result) w = MultiStepWorkflow(verbose=False) result = await w.run() result ``` ### Drawing Workflows We can also draw workflows. Let's use the `draw_all_possible_flows` function to draw the workflow. This stores the workflow in an HTML file. ```python from llama_index.utils.workflow import draw_all_possible_flows w = ... # as defined in the previous section draw_all_possible_flows(w, "flow.html") ``` ![workflow drawing](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/workflow-draw.png) There is one last cool trick that we will cover in the course, which is the ability to add state to the workflow. ### State Management State management is useful when you want to keep track of the state of the workflow, so that every step has access to the same state. We can do this by using the `Context` type hint on top of a parameter in the step function. ```python from llama_index.core.workflow import Context, StartEvent, StopEvent @step async def query(self, ctx: Context, ev: StartEvent) -> StopEvent: # store query in the context await ctx.store.set("query", "What is the capital of France?") # do something with context and event val = ... # retrieve query from the context query = await ctx.store.get("query") return StopEvent(result=val) ``` Great! Now you know how to create basic workflows in LlamaIndex! > [!TIP] > There are some more complex nuances to workflows, which you can learn about in the LlamaIndex documentation. However, there is another way to create workflows, which relies on the `AgentWorkflow` class. Let's take a look at how we can use this to create a multi-agent workflow. ## Automating workflows with Multi-Agent Workflows Instead of manual workflow creation, we can use the **`AgentWorkflow` class to create a multi-agent workflow**. The `AgentWorkflow` uses Workflow Agents to allow you to create a system of one or more agents that can collaborate and hand off tasks to each other based on their specialized capabilities. This enables building complex agent systems where different agents handle different aspects of a task. Instead of importing classes from `llama_index.core.agent`, we will import the agent classes from `llama_index.core.agent.workflow`. One agent must be designated as the root agent in the `AgentWorkflow` constructor. When a user message comes in, it is first routed to the root agent. Each agent can then: - Handle the request directly using their tools - Handoff to another agent better suited for the task - Return a response to the user Let's see how to create a multi-agent workflow. ```python from llama_index.core.agent.workflow import AgentWorkflow, ReActAgent from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI # Define some tools def add(a: int, b: int) -> int: """Add two numbers.""" return a + b def multiply(a: int, b: int) -> int: """Multiply two numbers.""" return a * b llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") # we can pass functions directly without FunctionTool -- the fn/docstring are parsed for the name/description multiply_agent = ReActAgent( name="multiply_agent", description="Is able to multiply two integers", system_prompt="A helpful assistant that can use a tool to multiply numbers.", tools=[multiply], llm=llm, ) addition_agent = ReActAgent( name="add_agent", description="Is able to add two integers", system_prompt="A helpful assistant that can use a tool to add numbers.", tools=[add], llm=llm, ) # Create the workflow workflow = AgentWorkflow( agents=[multiply_agent, addition_agent], root_agent="multiply_agent", ) # Run the system response = await workflow.run(user_msg="Can you add 5 and 3?") ``` Agent tools can also modify the workflow state we mentioned earlier. Before starting the workflow, we can provide an initial state dict that will be available to all agents. The state is stored in the state key of the workflow context. It will be injected into the state_prompt which augments each new user message. Let's inject a counter to count function calls by modifying the previous example: ```python from llama_index.core.workflow import Context # Define some tools async def add(ctx: Context, a: int, b: int) -> int: """Add two numbers.""" # update our count cur_state = await ctx.store.get("state") cur_state["num_fn_calls"] += 1 await ctx.store.set("state", cur_state) return a + b async def multiply(ctx: Context, a: int, b: int) -> int: """Multiply two numbers.""" # update our count cur_state = await ctx.store.get("state") cur_state["num_fn_calls"] += 1 await ctx.store.set("state", cur_state) return a * b ... workflow = AgentWorkflow( agents=[multiply_agent, addition_agent], root_agent="multiply_agent", initial_state={"num_fn_calls": 0}, state_prompt="Current state: {state}. User message: {msg}", ) # run the workflow with context ctx = Context(workflow) response = await workflow.run(user_msg="Can you add 5 and 3?", ctx=ctx) # pull out and inspect the state state = await ctx.store.get("state") print(state["num_fn_calls"]) ``` Congratulations! You have now mastered the basics of Agents in LlamaIndex! 🎉 Let's continue with one final quiz to solidify your knowledge! 🚀 ================================================ FILE: units/en/unit2/smolagents/code_agents.mdx ================================================ # Building Agents That Use Code Code agents are the default agent type in `smolagents`. They generate Python tool calls to perform actions, achieving action representations that are efficient, expressive, and accurate. Their streamlined approach reduces the number of required actions, simplifies complex operations, and enables reuse of existing code functions. `smolagents` provides a lightweight framework for building code agents, implemented in approximately 1,000 lines of code. ![Code vs JSON Actions](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/code_vs_json_actions.png) Graphic from the paper [Executable Code Actions Elicit Better LLM Agents](https://huggingface.co/papers/2402.01030) > [!TIP] > If you want to learn more about why code agents are effective, check out this guide from the smolagents documentation. ## Why Code Agents? In a multi-step agent process, the LLM writes and executes actions, typically involving external tool calls. Traditional approaches use a JSON format to specify tool names and arguments as strings, **which the system must parse to determine which tool to execute**. However, research shows that **tool-calling LLMs work more effectively with code directly**. This is a core principle of `smolagents`, as shown in the diagram above from [Executable Code Actions Elicit Better LLM Agents](https://huggingface.co/papers/2402.01030). Writing actions in code rather than JSON offers several key advantages: * **Composability**: Easily combine and reuse actions * **Object Management**: Work directly with complex structures like images * **Generality**: Express any computationally possible task * **Natural for LLMs**: High-quality code is already present in LLM training data ## How Does a Code Agent Work? ![From https://huggingface.co/docs/smolagents/conceptual_guides/react](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/smolagents/codeagent_docs.png) The diagram above illustrates how `CodeAgent.run()` operates, following the ReAct framework we mentioned in Unit 1. The main abstraction for agents in `smolagents` is a `MultiStepAgent`, which serves as the core building block. `CodeAgent` is a special kind of `MultiStepAgent`, as we will see in an example below. A `CodeAgent` performs actions through a cycle of steps, with existing variables and knowledge being incorporated into the agent's context, which is kept in an execution log: 1. The system prompt is stored in a `SystemPromptStep`, and the user query is logged in a `TaskStep`. 2. Then, the following while loop is executed: 2.1 Method `agent.write_memory_to_messages()` writes the agent's logs into a list of LLM-readable [chat messages](https://huggingface.co/docs/transformers/main/en/chat_templating). 2.2 These messages are sent to a `Model`, which generates a completion. 2.3 The completion is parsed to extract the action, which, in our case, should be a code snippet since we're working with a `CodeAgent`. 2.4 The action is executed. 2.5 The results are logged into memory in an `ActionStep`. At the end of each step, if the agent includes any function calls (in `agent.step_callback`), they are executed. ## Let's See Some Examples > [!TIP] > You can follow the code in this notebook that you can run using Google Colab. Alfred is planning a party at the Wayne family mansion and needs your help to ensure everything goes smoothly. To assist him, we'll apply what we've learned about how a multi-step `CodeAgent` operates. Alfred Party If you haven't installed `smolagents` yet, you can do so by running the following command: ```bash pip install smolagents -U ``` Let's also login to the Hugging Face Hub to have access to the Serverless Inference API. ```python from huggingface_hub import login login() ``` ### Selecting a Playlist for the Party Using `smolagents` Music is an essential part of a successful party! Alfred needs some help selecting the playlist. Luckily, `smolagents` has got us covered! We can build an agent capable of searching the web using DuckDuckGo. To give the agent access to this tool, we include it in the tool list when creating the agent. Alfred Playlist For the model, we'll rely on `InferenceClientModel`, which provides access to Hugging Face's [Serverless Inference API](https://huggingface.co/docs/api-inference/index). The default model is `"Qwen/Qwen2.5-Coder-32B-Instruct"`, which is performant and available for fast inference, but you can select any compatible model from the Hub. Running an agent is quite straightforward: ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel agent = CodeAgent(tools=[DuckDuckGoSearchTool()], model=InferenceClientModel()) agent.run("Search for the best music recommendations for a party at the Wayne's mansion.") ``` When you run this example, the output will **display a trace of the workflow steps being executed**. It will also print the corresponding Python code with the message: ```python ─ Executing parsed code: ──────────────────────────────────────────────────────────────────────────────────────── results = web_search(query="best music for a Batman party") print(results) ───────────────────────────────────────────────────────────────────────────────────────────────────────────────── ``` After a few steps, you'll see the generated playlist that Alfred can use for the party! 🎵 ### Using a Custom Tool to Prepare the Menu Alfred Menu Now that we have selected a playlist, we need to organize the menu for the guests. Again, Alfred can take advantage of `smolagents` to do so. Here, we use the `@tool` decorator to define a custom function that acts as a tool. We'll cover tool creation in more detail later, so for now, we can simply run the code. As you can see in the example below, we will create a tool using the `@tool` decorator and include it in the `tools` list. ```python from smolagents import CodeAgent, tool, InferenceClientModel # Tool to suggest a menu based on the occasion @tool def suggest_menu(occasion: str) -> str: """ Suggests a menu based on the occasion. Args: occasion (str): The type of occasion for the party. Allowed values are: - "casual": Menu for casual party. - "formal": Menu for formal party. - "superhero": Menu for superhero party. - "custom": Custom menu. """ if occasion == "casual": return "Pizza, snacks, and drinks." elif occasion == "formal": return "3-course dinner with wine and dessert." elif occasion == "superhero": return "Buffet with high-energy and healthy food." else: return "Custom menu for the butler." # Alfred, the butler, preparing the menu for the party agent = CodeAgent(tools=[suggest_menu], model=InferenceClientModel()) # Preparing the menu for the party agent.run("Prepare a formal menu for the party.") ``` The agent will run for a few steps until finding the answer. Precising allowed values in the docstring helps direct agent to `occasion` argument values which exist and limit hallucinations. The menu is ready! 🥗 ### Using Python Imports Inside the Agent We have the playlist and menu ready, but we need to check one more crucial detail: preparation time! Alfred needs to calculate when everything would be ready if he started preparing now, in case they need assistance from other superheroes. `smolagents` specializes in agents that write and execute Python code snippets, offering sandboxed execution for security. **Code execution has strict security measures** - imports outside a predefined safe list are blocked by default. However, you can authorize additional imports by passing them as strings in `additional_authorized_imports`. For more details on secure code execution, see the official [guide](https://huggingface.co/docs/smolagents/tutorials/secure_code_execution). When creating the agent, we'll use `additional_authorized_imports` to allow for importing the `datetime` module. ```python from smolagents import CodeAgent, InferenceClientModel import numpy as np import time import datetime agent = CodeAgent(tools=[], model=InferenceClientModel(), additional_authorized_imports=['datetime']) agent.run( """ Alfred needs to prepare for the party. Here are the tasks: 1. Prepare the drinks - 30 minutes 2. Decorate the mansion - 60 minutes 3. Set up the menu - 45 minutes 4. Prepare the music and playlist - 45 minutes If we start right now, at what time will the party be ready? """ ) ``` These examples are just the beginning of what you can do with code agents, and we're already starting to see their utility for preparing the party. You can learn more about how to build code agents in the [smolagents documentation](https://huggingface.co/docs/smolagents). In summary, `smolagents` specializes in agents that write and execute Python code snippets, offering sandboxed execution for security. It supports both local and API-based language models, making it adaptable to various development environments. ### Sharing Our Custom Party Preparator Agent to the Hub Wouldn't it be **amazing to share our very own Alfred agent with the community**? By doing so, anyone can easily download and use the agent directly from the Hub, bringing the ultimate party planner of Gotham to their fingertips! Let's make it happen! 🎉 The `smolagents` library makes this possible by allowing you to share a complete agent with the community and download others for immediate use. It's as simple as the following: ```python # Change to your username and repo name agent.push_to_hub('sergiopaniego/AlfredAgent') ``` To download the agent again, use the code below: ```python # Change to your username and repo name alfred_agent = agent.from_hub('sergiopaniego/AlfredAgent', trust_remote_code=True) alfred_agent.run("Give me the best playlist for a party at Wayne's mansion. The party idea is a 'villain masquerade' theme") ``` What's also exciting is that shared agents are directly available as Hugging Face Spaces, allowing you to interact with them in real-time. You can explore other agents [here](https://huggingface.co/spaces/davidberenstein1957/smolagents-and-tools). For example, the _AlfredAgent_ is available [here](https://huggingface.co/spaces/sergiopaniego/AlfredAgent). You can try it out directly below: You may be wondering—how did Alfred build such an agent using `smolagents`? By integrating several tools, he can generate an agent as follows. Don't worry about the tools for now, as we'll have a dedicated section later in this unit to explore that in detail: ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, FinalAnswerTool, InferenceClientModel, Tool, tool, VisitWebpageTool @tool def suggest_menu(occasion: str) -> str: """ Suggests a menu based on the occasion. Args: occasion: The type of occasion for the party. """ if occasion == "casual": return "Pizza, snacks, and drinks." elif occasion == "formal": return "3-course dinner with wine and dessert." elif occasion == "superhero": return "Buffet with high-energy and healthy food." else: return "Custom menu for the butler." @tool def catering_service_tool(query: str) -> str: """ This tool returns the highest-rated catering service in Gotham City. Args: query: A search term for finding catering services. """ # Example list of catering services and their ratings services = { "Gotham Catering Co.": 4.9, "Wayne Manor Catering": 4.8, "Gotham City Events": 4.7, } # Find the highest rated catering service (simulating search query filtering) best_service = max(services, key=services.get) return best_service class SuperheroPartyThemeTool(Tool): name = "superhero_party_theme_generator" description = """ This tool suggests creative superhero-themed party ideas based on a category. It returns a unique party theme idea.""" inputs = { "category": { "type": "string", "description": "The type of superhero party (e.g., 'classic heroes', 'villain masquerade', 'futuristic Gotham').", } } output_type = "string" def forward(self, category: str): themes = { "classic heroes": "Justice League Gala: Guests come dressed as their favorite DC heroes with themed cocktails like 'The Kryptonite Punch'.", "villain masquerade": "Gotham Rogues' Ball: A mysterious masquerade where guests dress as classic Batman villains.", "futuristic Gotham": "Neo-Gotham Night: A cyberpunk-style party inspired by Batman Beyond, with neon decorations and futuristic gadgets." } return themes.get(category.lower(), "Themed party idea not found. Try 'classic heroes', 'villain masquerade', or 'futuristic Gotham'.") # Alfred, the butler, preparing the menu for the party agent = CodeAgent( tools=[ DuckDuckGoSearchTool(), VisitWebpageTool(), suggest_menu, catering_service_tool, SuperheroPartyThemeTool(), FinalAnswerTool() ], model=InferenceClientModel(), max_steps=10, verbosity_level=2 ) agent.run("Give me the best playlist for a party at the Wayne's mansion. The party idea is a 'villain masquerade' theme") ``` As you can see, we've created a `CodeAgent` with several tools that enhance the agent's functionality, turning it into the ultimate party planner ready to share with the community! 🎉 Now, it's your turn: build your very own agent and share it with the community using the knowledge we've just learned! 🕵️‍♂️💡 > [!TIP] > If you would like to share your agent project, then make a space and tag the agents-course on the Hugging Face Hub. We'd love to see what you've created! ### Inspecting Our Party Preparator Agent with OpenTelemetry and Langfuse 📡 As Alfred fine-tunes the Party Preparator Agent, he's growing weary of debugging its runs. Agents, by nature, are unpredictable and difficult to inspect. But since he aims to build the ultimate Party Preparator Agent and deploy it in production, he needs robust traceability for future monitoring and analysis. Once again, `smolagents` comes to the rescue! It embraces the [OpenTelemetry](https://opentelemetry.io/) standard for instrumenting agent runs, allowing seamless inspection and logging. With the help of [Langfuse](https://langfuse.com/) and the `SmolagentsInstrumentor`, Alfred can easily track and analyze his agent’s behavior. Setting it up is straightforward! First, we need to install the necessary dependencies: ```bash pip install opentelemetry-sdk opentelemetry-exporter-otlp openinference-instrumentation-smolagents langfuse ``` Next, Alfred has already created an account on Langfuse and has his API keys ready. If you haven’t done so yet, you can sign up for Langfuse Cloud [here](https://cloud.langfuse.com/) or explore [alternatives](https://huggingface.co/docs/smolagents/tutorials/inspect_runs). Once you have your API keys, they need to be properly configured as follows: ```python import os # Get keys for your project from the project settings page: https://cloud.langfuse.com os.environ["LANGFUSE_PUBLIC_KEY"] = "pk-lf-..." os.environ["LANGFUSE_SECRET_KEY"] = "sk-lf-..." os.environ["LANGFUSE_HOST"] = "https://cloud.langfuse.com" # 🇪🇺 EU region # os.environ["LANGFUSE_HOST"] = "https://us.cloud.langfuse.com" # 🇺🇸 US region ``` With the environment variables set, we can now initialize the Langfuse client. get_client() initializes the Langfuse client using the credentials provided in the environment variables. ```python from langfuse import get_client langfuse = get_client() # Verify connection if langfuse.auth_check(): print("Langfuse client is authenticated and ready!") else: print("Authentication failed. Please check your credentials and host.") ``` Finally, Alfred is ready to initialize the `SmolagentsInstrumentor` and start tracking his agent's performance. ```python from openinference.instrumentation.smolagents import SmolagentsInstrumentor SmolagentsInstrumentor().instrument() ``` Alfred is now connected 🔌! The runs from `smolagents` are being logged in Langfuse, giving him full visibility into the agent's behavior. With this setup, he's ready to revisit previous runs and refine his Party Preparator Agent even further. > [!TIP] > To learn more about tracing your agents and using the collected data to evaluate their performance, check out Bonus Unit 2. ```python from smolagents import CodeAgent, InferenceClientModel agent = CodeAgent(tools=[], model=InferenceClientModel()) alfred_agent = agent.from_hub('sergiopaniego/AlfredAgent', trust_remote_code=True) alfred_agent.run("Give me the best playlist for a party at Wayne's mansion. The party idea is a 'villain masquerade' theme") ``` Alfred can now access these logs [here](https://cloud.langfuse.com/project/cm7bq0abj025rad078ak3luwi/traces/995fc019255528e4f48cf6770b0ce27b?timestamp=2025-02-19T10%3A28%3A36.929Z) to review and analyze them. > [!TIP] > Actually, a minor error occurred during execution. Can you spot it in the logs? Try to track how the agent handles it and still returns a valid answer. Here is the direct link to the error if you want to verify your answer. Of course the error has been fixed in the meantime, more details can be found in this issue. Meanwhile, the [suggested playlist](https://open.spotify.com/playlist/0gZMMHjuxMrrybQ7wTMTpw) sets the perfect vibe for the party preparations. Cool, right? 🎶 --- Now that we have created our first Code Agent, let's **learn how we can create Tool Calling Agents**, the second type of agent available in `smolagents`. ## Resources - [smolagents Blog](https://huggingface.co/blog/smolagents) - Introduction to smolagents and code interactions - [smolagents: Building Good Agents](https://huggingface.co/docs/smolagents/tutorials/building_good_agents) - Best practices for reliable agents - [Building Effective Agents - Anthropic](https://www.anthropic.com/research/building-effective-agents) - Agent design principles - [Sharing runs with OpenTelemetry](https://huggingface.co/docs/smolagents/tutorials/inspect_runs) - Details about how to setup OpenTelemetry for tracking your agents. ================================================ FILE: units/en/unit2/smolagents/conclusion.mdx ================================================ # Conclusion Congratulations on finishing the `smolagents` module of this second Unit 🥳 You’ve just mastered the fundamentals of `smolagents` and you’ve built your own Agent! Now that you have skills in `smolagents`, you can now start to create Agents that will solve tasks you're interested about. In the next module, you're going to learn **how to build Agents with LlamaIndex**. Finally, we would love **to hear what you think of the course and how we can improve it**. If you have some feedback then, please 👉 [fill this form](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ### Keep Learning, stay awesome 🤗 ================================================ FILE: units/en/unit2/smolagents/final_quiz.mdx ================================================ # Exam Time! Well done on working through the material on `smolagents`! You've already achieved a lot. Now, it's time to put your knowledge to the test with a quiz. 🧠 ## Instructions - The quiz consists of code questions. - You will be given instructions to complete the code snippets. - Read the instructions carefully and complete the code snippets accordingly. - For each question, you will be given the result and some feedback. 🧘 **This quiz is ungraded and uncertified**. It's about you understanding the `smolagents` library and knowing whether you should spend more time on the written material. In the coming units you'll put this knowledge to the test in use cases and projects. Let's get started! ## Quiz 🚀 You can also access the quiz 👉 [here](https://huggingface.co/spaces/agents-course/unit2_smolagents_quiz) ================================================ FILE: units/en/unit2/smolagents/introduction.mdx ================================================ # Introduction to `smolagents` Unit 2.1 Thumbnail Welcome to this module, where you'll learn **how to build effective agents** using the [`smolagents`](https://github.com/huggingface/smolagents) library, which provides a lightweight framework for creating capable AI agents. `smolagents` is a Hugging Face library; therefore, we would appreciate your support by **starring** the smolagents [`repository`](https://github.com/huggingface/smolagents) : staring smolagents ## Module Overview This module provides a comprehensive overview of key concepts and practical strategies for building intelligent agents using `smolagents`. With so many open-source frameworks available, it's essential to understand the components and capabilities that make `smolagents` a useful option or to determine when another solution might be a better fit. We'll explore critical agent types, including code agents designed for software development tasks, tool calling agents for creating modular, function-driven workflows, and retrieval agents that access and synthesize information. Additionally, we'll cover the orchestration of multiple agents as well as the integration of vision capabilities and web browsing, which unlock new possibilities for dynamic and context-aware applications. In this unit, Alfred, the agent from Unit 1, makes his return. This time, he’s using the `smolagents` framework for his internal workings. Together, we’ll explore the key concepts behind this framework as Alfred tackles various tasks. Alfred is organizing a party at the Wayne Manor while the Wayne family 🦇 is away, and he has plenty to do. Join us as we showcase his journey and how he handles these tasks with `smolagents`! > [!TIP] > In this unit, you will learn to build AI agents with the `smolagents` library. Your agents will be able to search for data, execute code, and interact with web pages. You will also learn how to combine multiple agents to create more powerful systems. ![Alfred the agent](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit1/this-is-alfred.jpg) ## Contents During this unit on `smolagents`, we cover: ### 1️⃣ [Why Use smolagents](./why_use_smolagents) `smolagents` is one of the many open-source agent frameworks available for application development. Alternative options include `LlamaIndex` and `LangGraph`, which are also covered in other modules in this course. `smolagents` offers several key features that might make it a great fit for specific use cases, but we should always consider all options when selecting a framework. We'll explore the advantages and drawbacks of using `smolagents`, helping you make an informed decision based on your project's requirements. ### 2️⃣ [CodeAgents](./code_agents) `CodeAgents` are the primary type of agent in `smolagents`. Instead of generating JSON or text, these agents produce Python code to perform actions. This module explores their purpose, functionality, and how they work, along with hands-on examples to showcase their capabilities. ### 3️⃣ [ToolCallingAgents](./tool_calling_agents) `ToolCallingAgents` are the second type of agent supported by `smolagents`. Unlike `CodeAgents`, which generate Python code, these agents rely on JSON/text blobs that the system must parse and interpret to execute actions. This module covers their functionality, their key differences from `CodeAgents`, and it provides an example to illustrate their usage. ### 4️⃣ [Tools](./tools) As we saw in Unit 1, tools are functions that an LLM can use within an agentic system, and they act as the essential building blocks for agent behavior. This module covers how to create tools, their structure, and different implementation methods using the `Tool` class or the `@tool` decorator. You'll also learn about the default toolbox, how to share tools with the community, and how to load community-contributed tools for use in your agents. ### 5️⃣ [Retrieval Agents](./retrieval_agents) Retrieval agents allow models access to knowledge bases, making it possible to search, synthesize, and retrieve information from multiple sources. They leverage vector stores for efficient retrieval and implement **Retrieval-Augmented Generation (RAG)** patterns. These agents are particularly useful for integrating web search with custom knowledge bases while maintaining conversation context through memory systems. This module explores implementation strategies, including fallback mechanisms for robust information retrieval. ### 6️⃣ [Multi-Agent Systems](./multi_agent_systems) Orchestrating multiple agents effectively is crucial for building powerful, multi-agent systems. By combining agents with different capabilities—such as a web search agent with a code execution agent—you can create more sophisticated solutions. This module focuses on designing, implementing, and managing multi-agent systems to maximize efficiency and reliability. ### 7️⃣ [Vision and Browser agents](./vision_agents) Vision agents extend traditional agent capabilities by incorporating **Vision-Language Models (VLMs)**, enabling them to process and interpret visual information. This module explores how to design and integrate VLM-powered agents, unlocking advanced functionalities like image-based reasoning, visual data analysis, and multimodal interactions. We will also use vision agents to build a browser agent that can browse the web and extract information from it. ## Resources - [smolagents Documentation](https://huggingface.co/docs/smolagents) - Official docs for the smolagents library - [Building Effective Agents](https://www.anthropic.com/research/building-effective-agents) - Research paper on agent architectures - [Agent Guidelines](https://huggingface.co/docs/smolagents/tutorials/building_good_agents) - Best practices for building reliable agents - [LangGraph Agents](https://langchain-ai.github.io/langgraph/) - Additional examples of agent implementations - [Function Calling Guide](https://platform.openai.com/docs/guides/function-calling) - Understanding function calling in LLMs - [RAG Best Practices](https://www.pinecone.io/learn/retrieval-augmented-generation/) - Guide to implementing effective RAG ================================================ FILE: units/en/unit2/smolagents/multi_agent_systems.mdx ================================================ # Multi-Agent Systems Multi-agent systems enable **specialized agents to collaborate on complex tasks**, improving modularity, scalability, and robustness. Instead of relying on a single agent, tasks are distributed among agents with distinct capabilities. In **smolagents**, different agents can be combined to generate Python code, call external tools, perform web searches, and more. By orchestrating these agents, we can create powerful workflows. A typical setup might include: - A **Manager Agent** for task delegation - A **Code Interpreter Agent** for code execution - A **Web Search Agent** for information retrieval The diagram below illustrates a simple multi-agent architecture where a **Manager Agent** coordinates a **Code Interpreter Tool** and a **Web Search Agent**, which in turn utilizes tools like the `DuckDuckGoSearchTool` and `VisitWebpageTool` to gather relevant information. ## Multi-Agent Systems in Action A multi-agent system consists of multiple specialized agents working together under the coordination of an **Orchestrator Agent**. This approach enables complex workflows by distributing tasks among agents with distinct roles. For example, a **Multi-Agent RAG system** can integrate: - A **Web Agent** for browsing the internet. - A **Retriever Agent** for fetching information from knowledge bases. - An **Image Generation Agent** for producing visuals. All of these agents operate under an orchestrator that manages task delegation and interaction. ## Solving a complex task with a multi-agent hierarchy > [!TIP] > You can follow the code in this notebook that you can run using Google Colab. The reception is approaching! With your help, Alfred is now nearly finished with the preparations. But now there's a problem: the Batmobile has disappeared. Alfred needs to find a replacement, and find it quickly. Fortunately, a few biopics have been done on Bruce Wayne's life, so maybe Alfred could get a car left behind on one of the movie sets, and re-engineer it up to modern standards, which certainly would include a full self-driving option. But this could be anywhere in the filming locations around the world - which could be numerous. So Alfred wants your help. Could you build an agent able to solve this task? > 👉 Find all Batman filming locations in the world, calculate the time to transfer via boat to there, and represent them on a map, with a color varying by boat transfer time. Also represent some supercar factories with the same boat transfer time. Let's build this! This example needs some additional packages, so let's install them first: ```bash pip install 'smolagents[litellm]' plotly geopandas shapely kaleido -q ``` ### We first make a tool to get the cargo plane transfer time. ```python import math from typing import Optional, Tuple from smolagents import tool @tool def calculate_cargo_travel_time( origin_coords: Tuple[float, float], destination_coords: Tuple[float, float], cruising_speed_kmh: Optional[float] = 750.0, # Average speed for cargo planes ) -> float: """ Calculate the travel time for a cargo plane between two points on Earth using great-circle distance. Args: origin_coords: Tuple of (latitude, longitude) for the starting point destination_coords: Tuple of (latitude, longitude) for the destination cruising_speed_kmh: Optional cruising speed in km/h (defaults to 750 km/h for typical cargo planes) Returns: float: The estimated travel time in hours Example: >>> # Chicago (41.8781° N, 87.6298° W) to Sydney (33.8688° S, 151.2093° E) >>> result = calculate_cargo_travel_time((41.8781, -87.6298), (-33.8688, 151.2093)) """ def to_radians(degrees: float) -> float: return degrees * (math.pi / 180) # Extract coordinates lat1, lon1 = map(to_radians, origin_coords) lat2, lon2 = map(to_radians, destination_coords) # Earth's radius in kilometers EARTH_RADIUS_KM = 6371.0 # Calculate great-circle distance using the haversine formula dlon = lon2 - lon1 dlat = lat2 - lat1 a = ( math.sin(dlat / 2) ** 2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2) ** 2 ) c = 2 * math.asin(math.sqrt(a)) distance = EARTH_RADIUS_KM * c # Add 10% to account for non-direct routes and air traffic controls actual_distance = distance * 1.1 # Calculate flight time # Add 1 hour for takeoff and landing procedures flight_time = (actual_distance / cruising_speed_kmh) + 1.0 # Format the results return round(flight_time, 2) print(calculate_cargo_travel_time((41.8781, -87.6298), (-33.8688, 151.2093))) ``` ### Setting up the agent For the model provider, we use Together AI, one of the new [inference providers on the Hub](https://huggingface.co/blog/inference-providers)! The GoogleSearchTool uses the [Serper API](https://serper.dev) to search the web, so this requires either having setup env variable `SERPAPI_API_KEY` and passing `provider="serpapi"` or having `SERPER_API_KEY` and passing `provider=serper`. If you don't have any Serp API provider setup, you can use `DuckDuckGoSearchTool` but beware that it has a rate limit. ```python import os from PIL import Image from smolagents import CodeAgent, GoogleSearchTool, InferenceClientModel, VisitWebpageTool model = InferenceClientModel(model_id="Qwen/Qwen2.5-Coder-32B-Instruct", provider="together") ``` We can start by creating a simple agent as a baseline to give us a simple report. ```python task = """Find all Batman filming locations in the world, calculate the time to transfer via cargo plane to here (we're in Gotham, 40.7128° N, 74.0060° W), and return them to me as a pandas dataframe. Also give me some supercar factories with the same cargo plane transfer time.""" ``` ```python agent = CodeAgent( model=model, tools=[GoogleSearchTool("serper"), VisitWebpageTool(), calculate_cargo_travel_time], additional_authorized_imports=["pandas"], max_steps=20, ) ``` ```python result = agent.run(task) ``` ```python result ``` In our case, it generates this output: ```python | | Location | Travel Time to Gotham (hours) | |--|------------------------------------------------------|------------------------------| | 0 | Necropolis Cemetery, Glasgow, Scotland, UK | 8.60 | | 1 | St. George's Hall, Liverpool, England, UK | 8.81 | | 2 | Two Temple Place, London, England, UK | 9.17 | | 3 | Wollaton Hall, Nottingham, England, UK | 9.00 | | 4 | Knebworth House, Knebworth, Hertfordshire, UK | 9.15 | | 5 | Acton Lane Power Station, Acton Lane, Acton, UK | 9.16 | | 6 | Queensboro Bridge, New York City, USA | 1.01 | | 7 | Wall Street, New York City, USA | 1.00 | | 8 | Mehrangarh Fort, Jodhpur, Rajasthan, India | 18.34 | | 9 | Turda Gorge, Turda, Romania | 11.89 | | 10 | Chicago, USA | 2.68 | | 11 | Hong Kong, China | 19.99 | | 12 | Cardington Studios, Northamptonshire, UK | 9.10 | | 13 | Warner Bros. Leavesden Studios, Hertfordshire, UK | 9.13 | | 14 | Westwood, Los Angeles, CA, USA | 6.79 | | 15 | Woking, UK (McLaren) | 9.13 | ``` We could already improve this a bit by throwing in some dedicated planning steps, and adding more prompting. Planning steps allow the agent to think ahead and plan its next steps, which can be useful for more complex tasks. ```python agent.planning_interval = 4 detailed_report = agent.run(f""" You're an expert analyst. You make comprehensive reports after visiting many websites. Don't hesitate to search for many queries at once in a for loop. For each data point that you find, visit the source url to confirm numbers. {task} """) print(detailed_report) ``` ```python detailed_report ``` In our case, it generates this output: ```python | | Location | Travel Time (hours) | |--|--------------------------------------------------|---------------------| | 0 | Bridge of Sighs, Glasgow Necropolis, Glasgow, UK | 8.6 | | 1 | Wishart Street, Glasgow, Scotland, UK | 8.6 | ``` Thanks to these quick changes, we obtained a much more concise report by simply providing our agent a detailed prompt, and giving it planning capabilities! The model's context window is quickly filling up. So **if we ask our agent to combine the results of detailed search with another, it will be slower and quickly ramp up tokens and costs**. ➡️ We need to improve the structure of our system. ### ✌️ Splitting the task between two agents Multi-agent structures allow to separate memories between different sub-tasks, with two great benefits: - Each agent is more focused on its core task, thus more performant - Separating memories reduces the count of input tokens at each step, thus reducing latency and cost. Let's create a team with a dedicated web search agent, managed by another agent. The manager agent should have plotting capabilities to write its final report: so let us give it access to additional imports, including `plotly`, and `geopandas` + `shapely` for spatial plotting. ```python model = InferenceClientModel( "Qwen/Qwen2.5-Coder-32B-Instruct", provider="together", max_tokens=8096 ) web_agent = CodeAgent( model=model, tools=[ GoogleSearchTool(provider="serper"), VisitWebpageTool(), calculate_cargo_travel_time, ], name="web_agent", description="Browses the web to find information", verbosity_level=0, max_steps=10, ) ``` The manager agent will need to do some mental heavy lifting. So we give it the stronger model [DeepSeek-R1](https://huggingface.co/deepseek-ai/DeepSeek-R1), and add a `planning_interval` to the mix. ```python from smolagents.utils import encode_image_base64, make_image_url from smolagents import OpenAIServerModel def check_reasoning_and_plot(final_answer, agent_memory): multimodal_model = OpenAIServerModel("gpt-4o", max_tokens=8096) filepath = "saved_map.png" assert os.path.exists(filepath), "Make sure to save the plot under saved_map.png!" image = Image.open(filepath) prompt = ( f"Here is a user-given task and the agent steps: {agent_memory.get_succinct_steps()}. Now here is the plot that was made." "Please check that the reasoning process and plot are correct: do they correctly answer the given task?" "First list reasons why yes/no, then write your final decision: PASS in caps lock if it is satisfactory, FAIL if it is not." "Don't be harsh: if the plot mostly solves the task, it should pass." "To pass, a plot should be made using px.scatter_map and not any other method (scatter_map looks nicer)." ) messages = [ { "role": "user", "content": [ { "type": "text", "text": prompt, }, { "type": "image_url", "image_url": {"url": make_image_url(encode_image_base64(image))}, }, ], } ] output = multimodal_model(messages).content print("Feedback: ", output) if "FAIL" in output: raise Exception(output) return True manager_agent = CodeAgent( model=InferenceClientModel("deepseek-ai/DeepSeek-R1", provider="together", max_tokens=8096), tools=[calculate_cargo_travel_time], managed_agents=[web_agent], additional_authorized_imports=[ "geopandas", "plotly", "shapely", "json", "pandas", "numpy", ], planning_interval=5, verbosity_level=2, final_answer_checks=[check_reasoning_and_plot], max_steps=15, ) ``` Let us inspect what this team looks like: ```python manager_agent.visualize() ``` This will generate something like this, helping us understand the structure and relationship between agents and tools used: ```python CodeAgent | deepseek-ai/DeepSeek-R1 ├── ✅ Authorized imports: ['geopandas', 'plotly', 'shapely', 'json', 'pandas', 'numpy'] ├── 🛠️ Tools: │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ │ ┃ Name ┃ Description ┃ Arguments ┃ │ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ │ calculate_cargo_travel_time │ Calculate the travel time for a cargo │ origin_coords (`array`): Tuple of │ │ │ │ plane between two points on Earth │ (latitude, longitude) for the │ │ │ │ using great-circle distance. │ starting point │ │ │ │ │ destination_coords (`array`): Tuple │ │ │ │ │ of (latitude, longitude) for the │ │ │ │ │ destination │ │ │ │ │ cruising_speed_kmh (`number`): │ │ │ │ │ Optional cruising speed in km/h │ │ │ │ │ (defaults to 750 km/h for typical │ │ │ │ │ cargo planes) │ │ │ final_answer │ Provides a final answer to the given │ answer (`any`): The final answer to │ │ │ │ problem. │ the problem │ │ └─────────────────────────────┴───────────────────────────────────────┴───────────────────────────────────────┘ └── 🤖 Managed agents: └── web_agent | CodeAgent | Qwen/Qwen2.5-Coder-32B-Instruct ├── ✅ Authorized imports: [] ├── 📝 Description: Browses the web to find information └── 🛠️ Tools: ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ Name ┃ Description ┃ Arguments ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ web_search │ Performs a google web search for │ query (`string`): The search │ │ │ your query then returns a string │ query to perform. │ │ │ of the top search results. │ filter_year (`integer`): │ │ │ │ Optionally restrict results to a │ │ │ │ certain year │ │ visit_webpage │ Visits a webpage at the given url │ url (`string`): The url of the │ │ │ and reads its content as a │ webpage to visit. │ │ │ markdown string. Use this to │ │ │ │ browse webpages. │ │ │ calculate_cargo_travel_time │ Calculate the travel time for a │ origin_coords (`array`): Tuple of │ │ │ cargo plane between two points on │ (latitude, longitude) for the │ │ │ Earth using great-circle │ starting point │ │ │ distance. │ destination_coords (`array`): │ │ │ │ Tuple of (latitude, longitude) │ │ │ │ for the destination │ │ │ │ cruising_speed_kmh (`number`): │ │ │ │ Optional cruising speed in km/h │ │ │ │ (defaults to 750 km/h for typical │ │ │ │ cargo planes) │ │ final_answer │ Provides a final answer to the │ answer (`any`): The final answer │ │ │ given problem. │ to the problem │ └─────────────────────────────┴───────────────────────────────────┴───────────────────────────────────┘ ``` ```python manager_agent.run(""" Find all Batman filming locations in the world, calculate the time to transfer via cargo plane to here (we're in Gotham, 40.7128° N, 74.0060° W). Also give me some supercar factories with the same cargo plane transfer time. You need at least 6 points in total. Represent this as spatial map of the world, with the locations represented as scatter points with a color that depends on the travel time, and save it to saved_map.png! Here's an example of how to plot and return a map: import plotly.express as px df = px.data.carshare() fig = px.scatter_map(df, lat="centroid_lat", lon="centroid_lon", text="name", color="peak_hour", size=100, color_continuous_scale=px.colors.sequential.Magma, size_max=15, zoom=1) fig.show() fig.write_image("saved_image.png") final_answer(fig) Never try to process strings using code: when you have a string to read, just print it and you'll see it. """) ``` I don't know how that went in your run, but in mine, the manager agent skilfully divided tasks given to the web agent in `1. Search for Batman filming locations`, then `2. Find supercar factories`, before aggregating the lists and plotting the map. Let's see what the map looks like by inspecting it directly from the agent state: ```python manager_agent.python_executor.state["fig"] ``` This will output the map: ![Multiagent system example output map](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/smolagents/output_map.png) ## Resources - [Multi-Agent Systems](https://huggingface.co/docs/smolagents/main/en/examples/multiagents) – Overview of multi-agent systems. - [What is Agentic RAG?](https://weaviate.io/blog/what-is-agentic-rag) – Introduction to Agentic RAG. - [Multi-Agent RAG System 🤖🤝🤖 Recipe](https://huggingface.co/learn/cookbook/multiagent_rag_system) – Step-by-step guide to building a multi-agent RAG system. ================================================ FILE: units/en/unit2/smolagents/quiz1.mdx ================================================ # Small Quiz (ungraded) [[quiz1]] Let's test your understanding of `smolagents` with a quick quiz! Remember, testing yourself helps reinforce learning and identify areas that may need review. This is an optional quiz and it's not graded. ### Q1: What is one of the primary advantages of choosing `smolagents` over other frameworks? Which statement best captures a core strength of the `smolagents` approach? --- ### Q2: In which scenario would you likely benefit most from using smolagents? Which situation aligns well with what smolagents does best? --- ### Q3: smolagents offers flexibility in model integration. Which statement best reflects its approach? Choose the most accurate description of how smolagents interoperates with LLMs. --- ### Q4: How does smolagents handle the debate between code-based actions and JSON-based actions? Which statement correctly characterizes smolagents' philosophy about action formats? --- ### Q5: How does smolagents integrate with the Hugging Face Hub for added benefits? Which statement accurately describes one of the core advantages of Hub integration? --- Congratulations on completing this quiz! 🎉 If you missed any questions, consider reviewing the *Why use smolagents* section for a deeper understanding. If you did well, you're ready to explore more advanced topics in smolagents! ================================================ FILE: units/en/unit2/smolagents/quiz2.mdx ================================================ # Small Quiz (ungraded) [[quiz2]] It's time to test your understanding of the *Code Agents*, *Tool Calling Agents*, and *Tools* sections. This quiz is optional and not graded. --- ### Q1: What is the key difference between creating a tool with the `@tool` decorator versus creating a subclass of `Tool` in smolagents? Which statement best describes the distinction between these two approaches for defining tools? @tool decorator is mandatory for retrieval-based tools, while subclasses of Tool are only for text-generation tasks", explain: "Both approaches can be used for any type of tool, including retrieval-based or text-generation tools.", }, { text: "The @tool decorator is recommended for simple function-based tools, while subclasses of Tool offer more flexibility for complex functionality or custom metadata", explain: "This is correct. The decorator approach is simpler, but subclassing allows more customized behavior.", correct: true }, { text: "@tool can only be used in multi-agent systems, while creating a Tool subclass is for single-agent scenarios", explain: "All agents (single or multi) can use either approach to define tools; there is no such restriction.", }, { text: "Decorating a function with @tool replaces the need for a docstring, whereas subclasses must not include docstrings", explain: "Both methods benefit from clear docstrings. The decorator doesn't replace them, and a subclass can still have docstrings.", } ]} /> --- ### Q2: How does a CodeAgent handle multi-step tasks using the ReAct (Reason + Act) approach? Which statement correctly describes how the CodeAgent executes a series of steps to solve a task? --- ### Q3: Which of the following is a primary advantage of sharing a tool on the Hugging Face Hub? Select the best reason why a developer might upload and share their custom tool. --- ### Q4: ToolCallingAgent differs from CodeAgent in how it executes actions. Which statement is correct? Choose the option that accurately describes how ToolCallingAgent works. --- ### Q5: What is included in the smolagents default toolbox, and why might you use it? Which statement best captures the purpose and contents of the default toolbox in smolagents? --- Congratulations on completing this quiz! 🎉 If any questions gave you trouble, revisit the *Code Agents*, *Tool Calling Agents*, or *Tools* sections to strengthen your understanding. If you aced it, you're well on your way to building robust smolagents applications! ================================================ FILE: units/en/unit2/smolagents/retrieval_agents.mdx ================================================ # Building Agentic RAG Systems > [!TIP] > You can follow the code in this notebook that you can run using Google Colab. Retrieval Augmented Generation (RAG) systems combine the capabilities of data retrieval and generation models to provide context-aware responses. For example, a user's query is passed to a search engine, and the retrieved results are given to the model along with the query. The model then generates a response based on the query and retrieved information. Agentic RAG (Retrieval-Augmented Generation) extends traditional RAG systems by **combining autonomous agents with dynamic knowledge retrieval**. While traditional RAG systems use an LLM to answer queries based on retrieved data, agentic RAG **enables intelligent control of both retrieval and generation processes**, improving efficiency and accuracy. Traditional RAG systems face key limitations, such as **relying on a single retrieval step** and focusing on direct semantic similarity with the user’s query, which may overlook relevant information. Agentic RAG addresses these issues by allowing the agent to autonomously formulate search queries, critique retrieved results, and conduct multiple retrieval steps for a more tailored and comprehensive output. ## Basic Retrieval with DuckDuckGo Let's build a simple agent that can search the web using DuckDuckGo. This agent will retrieve information and synthesize responses to answer queries. With Agentic RAG, Alfred's agent can: * Search for latest superhero party trends * Refine results to include luxury elements * Synthesize information into a complete plan Here's how Alfred's agent can achieve this: ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel # Initialize the search tool search_tool = DuckDuckGoSearchTool() # Initialize the model model = InferenceClientModel() agent = CodeAgent( model=model, tools=[search_tool], ) # Example usage response = agent.run( "Search for luxury superhero-themed party ideas, including decorations, entertainment, and catering." ) print(response) ``` The agent follows this process: 1. **Analyzes the Request:** Alfred’s agent identifies the key elements of the query—luxury superhero-themed party planning, with focus on decor, entertainment, and catering. 2. **Performs Retrieval:** The agent leverages DuckDuckGo to search for the most relevant and up-to-date information, ensuring it aligns with Alfred’s refined preferences for a luxurious event. 3. **Synthesizes Information:** After gathering the results, the agent processes them into a cohesive, actionable plan for Alfred, covering all aspects of the party. 4. **Stores for Future Reference:** The agent stores the retrieved information for easy access when planning future events, optimizing efficiency in subsequent tasks. ## Custom Knowledge Base Tool For specialized tasks, a custom knowledge base can be invaluable. Let's create a tool that queries a vector database of technical documentation or specialized knowledge. Using semantic search, the agent can find the most relevant information for Alfred's needs. A vector database stores numerical representations (embeddings) of text or other data, created by machine learning models. It enables semantic search by identifying similar meanings in high-dimensional space. This approach combines predefined knowledge with semantic search to provide context-aware solutions for event planning. With specialized knowledge access, Alfred can perfect every detail of the party. In this example, we'll create a tool that retrieves party planning ideas from a custom knowledge base. We'll use a BM25 retriever to search the knowledge base and return the top results, and `RecursiveCharacterTextSplitter` to split the documents into smaller chunks for more efficient search. ```python from langchain_community.docstore.document import Document from langchain_text_splitters import RecursiveCharacterTextSplitter from smolagents import Tool from langchain_community.retrievers import BM25Retriever from smolagents import CodeAgent, InferenceClientModel class PartyPlanningRetrieverTool(Tool): name = "party_planning_retriever" description = "Uses semantic search to retrieve relevant party planning ideas for Alfred’s superhero-themed party at Wayne Manor." inputs = { "query": { "type": "string", "description": "The query to perform. This should be a query related to party planning or superhero themes.", } } output_type = "string" def __init__(self, docs, **kwargs): super().__init__(**kwargs) self.retriever = BM25Retriever.from_documents( docs, k=5 # Retrieve the top 5 documents ) def forward(self, query: str) -> str: assert isinstance(query, str), "Your search query must be a string" docs = self.retriever.invoke( query, ) return "\nRetrieved ideas:\n" + "".join( [ f"\n\n===== Idea {str(i)} =====\n" + doc.page_content for i, doc in enumerate(docs) ] ) # Simulate a knowledge base about party planning party_ideas = [ {"text": "A superhero-themed masquerade ball with luxury decor, including gold accents and velvet curtains.", "source": "Party Ideas 1"}, {"text": "Hire a professional DJ who can play themed music for superheroes like Batman and Wonder Woman.", "source": "Entertainment Ideas"}, {"text": "For catering, serve dishes named after superheroes, like 'The Hulk's Green Smoothie' and 'Iron Man's Power Steak.'", "source": "Catering Ideas"}, {"text": "Decorate with iconic superhero logos and projections of Gotham and other superhero cities around the venue.", "source": "Decoration Ideas"}, {"text": "Interactive experiences with VR where guests can engage in superhero simulations or compete in themed games.", "source": "Entertainment Ideas"} ] source_docs = [ Document(page_content=doc["text"], metadata={"source": doc["source"]}) for doc in party_ideas ] # Split the documents into smaller chunks for more efficient search text_splitter = RecursiveCharacterTextSplitter( chunk_size=500, chunk_overlap=50, add_start_index=True, strip_whitespace=True, separators=["\n\n", "\n", ".", " ", ""], ) docs_processed = text_splitter.split_documents(source_docs) # Create the retriever tool party_planning_retriever = PartyPlanningRetrieverTool(docs_processed) # Initialize the agent agent = CodeAgent(tools=[party_planning_retriever], model=InferenceClientModel()) # Example usage response = agent.run( "Find ideas for a luxury superhero-themed party, including entertainment, catering, and decoration options." ) print(response) ``` This enhanced agent can: 1. First check the documentation for relevant information 2. Combine insights from the knowledge base 3. Maintain conversation context in memory ## Enhanced Retrieval Capabilities When building agentic RAG systems, the agent can employ sophisticated strategies like: 1. **Query Reformulation:** Instead of using the raw user query, the agent can craft optimized search terms that better match the target documents 2. **Query Decomposition:** Instead of using the user query directly, if it contains multiple pieces of information to query, it can be decomposed to multiple queries 3. **Query Expansion:** Somehow similar to Query Reformulation but done multiple times to put the query in multiple wordings to query them all 4. **Reranking:** Using Cross-Encoders to assign more comprehensive and semantic relevance scores between retrieved documents and search query 5. **Multi-Step Retrieval:** The agent can perform multiple searches, using initial results to inform subsequent queries 6. **Source Integration:** Information can be combined from multiple sources like web search and local documentation 7. **Result Validation:** Retrieved content can be analyzed for relevance and accuracy before being included in responses Effective agentic RAG systems require careful consideration of several key aspects. The agent **should select between available tools based on the query type and context**. Memory systems help maintain conversation history and avoid repetitive retrievals. Having fallback strategies ensures the system can still provide value even when primary retrieval methods fail. Additionally, implementing validation steps helps ensure the accuracy and relevance of retrieved information. ## Resources - [Agentic RAG: turbocharge your RAG with query reformulation and self-query! 🚀](https://huggingface.co/learn/cookbook/agent_rag) - Recipe for developing an Agentic RAG system using smolagents. ================================================ FILE: units/en/unit2/smolagents/tool_calling_agents.mdx ================================================ # Writing actions as code snippets or JSON blobs > [!TIP] > You can follow the code in this notebook that you can run using Google Colab. Tool Calling Agents are the second type of agent available in `smolagents`. Unlike Code Agents that use Python snippets, these agents **use the built-in tool-calling capabilities of LLM providers** to generate tool calls as **JSON structures**. This is the standard approach used by OpenAI, Anthropic, and many other providers. Let's look at an example. When Alfred wants to search for catering services and party ideas, a `CodeAgent` would generate and run Python code like this: ```python for query in [ "Best catering services in Gotham City", "Party theme ideas for superheroes" ]: print(web_search(f"Search for: {query}")) ``` A `ToolCallingAgent` would instead create a JSON structure: ```python [ {"name": "web_search", "arguments": "Best catering services in Gotham City"}, {"name": "web_search", "arguments": "Party theme ideas for superheroes"} ] ``` This JSON blob is then used to execute the tool calls. While `smolagents` primarily focuses on `CodeAgents` since [they perform better overall](https://huggingface.co/papers/2402.01030), `ToolCallingAgents` can be effective for simple systems that don't require variable handling or complex tool calls. ![Code vs JSON Actions](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/code_vs_json_actions.png) ## How Do Tool Calling Agents Work? Tool Calling Agents follow the same multi-step workflow as Code Agents (see the [previous section](./code_agents) for details). The key difference is in **how they structure their actions**: instead of executable code, they **generate JSON objects that specify tool names and arguments**. The system then **parses these instructions** to execute the appropriate tools. ## Example: Running a Tool Calling Agent Let's revisit the previous example where Alfred started party preparations, but this time we'll use a `ToolCallingAgent` to highlight the difference. We'll build an agent that can search the web using DuckDuckGo, just like in our Code Agent example. The only difference is the agent type - the framework handles everything else: ```python from smolagents import ToolCallingAgent, WebSearchTool, InferenceClientModel agent = ToolCallingAgent(tools=[WebSearchTool()], model=InferenceClientModel()) agent.run("Search for the best music recommendations for a party at the Wayne's mansion.") ``` When you examine the agent's trace, instead of seeing `Executing parsed code:`, you'll see something like: ```text ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ Calling tool: 'web_search' with arguments: {'query': "best music recommendations for a party at Wayne's │ │ mansion"} │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ``` The agent generates a structured tool call that the system processes to produce the output, rather than directly executing code like a `CodeAgent`. Now that we understand both agent types, we can choose the right one for our needs. Let's continue exploring `smolagents` to make Alfred's party a success! 🎉 ## Resources - [ToolCallingAgent documentation](https://huggingface.co/docs/smolagents/v1.8.1/en/reference/agents#smolagents.ToolCallingAgent) - Official documentation for ToolCallingAgent ================================================ FILE: units/en/unit2/smolagents/tools.mdx ================================================ # Tools As we explored in [unit 1](https://huggingface.co/learn/agents-course/unit1/tools), agents use tools to perform various actions. In `smolagents`, tools are treated as **functions that an LLM can call within an agent system**. To interact with a tool, the LLM needs an **interface description** with these key components: - **Name**: What the tool is called - **Tool description**: What the tool does - **Input types and descriptions**: What arguments the tool accepts - **Output type**: What the tool returns For instance, while preparing for a party at Wayne Manor, Alfred needs various tools to gather information - from searching for catering services to finding party theme ideas. Here's how a simple search tool interface might look: - **Name:** `web_search` - **Tool description:** Searches the web for specific queries - **Input:** `query` (string) - The search term to look up - **Output:** String containing the search results By using these tools, Alfred can make informed decisions and gather all the information needed for planning the perfect party. Below, you can see an animation illustrating how a tool call is managed: ![Agentic pipeline from https://huggingface.co/docs/smolagents/conceptual_guides/react](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/Agent_ManimCE.gif) ## Tool Creation Methods In `smolagents`, tools can be defined in two ways: 1. **Using the `@tool` decorator** for simple function-based tools 2. **Creating a subclass of `Tool`** for more complex functionality ### The `@tool` Decorator The `@tool` decorator is the **recommended way to define simple tools**. Under the hood, smolagents will parse basic information about the function from Python. So if you name your function clearly and write a good docstring, it will be easier for the LLM to use. Using this approach, we define a function with: - **A clear and descriptive function name** that helps the LLM understand its purpose. - **Type hints for both inputs and outputs** to ensure proper usage. - **A detailed description**, including an `Args:` section where each argument is explicitly described. These descriptions provide valuable context for the LLM, so it's important to write them carefully. #### Generating a tool that retrieves the highest-rated catering Alfred Catering > [!TIP] > You can follow the code in this notebook that you can run using Google Colab. Let's imagine that Alfred has already decided on the menu for the party, but now he needs help preparing food for such a large number of guests. To do so, he would like to hire a catering service and needs to identify the highest-rated options available. Alfred can leverage a tool to search for the best catering services in his area. Below is an example of how Alfred can use the `@tool` decorator to make this happen: ```python from smolagents import CodeAgent, InferenceClientModel, tool # Let's pretend we have a function that fetches the highest-rated catering services. @tool def catering_service_tool(query: str) -> str: """ This tool returns the highest-rated catering service in Gotham City. Args: query: A search term for finding catering services. """ # Example list of catering services and their ratings services = { "Gotham Catering Co.": 4.9, "Wayne Manor Catering": 4.8, "Gotham City Events": 4.7, } # Find the highest rated catering service (simulating search query filtering) best_service = max(services, key=services.get) return best_service agent = CodeAgent(tools=[catering_service_tool], model=InferenceClientModel()) # Run the agent to find the best catering service result = agent.run( "Can you give me the name of the highest-rated catering service in Gotham City?" ) print(result) # Output: Gotham Catering Co. ``` ### Defining a Tool as a Python Class This approach involves creating a subclass of [`Tool`](https://huggingface.co/docs/smolagents/v1.8.1/en/reference/tools#smolagents.Tool). For complex tools, we can implement a class instead of a Python function. The class wraps the function with metadata that helps the LLM understand how to use it effectively. In this class, we define: - `name`: The tool's name. - `description`: A description used to populate the agent's system prompt. - `inputs`: A dictionary with keys `type` and `description`, providing information to help the Python interpreter process inputs. - `output_type`: Specifies the expected output type. - `forward`: The method containing the inference logic to execute. Below, we can see an example of a tool built using `Tool` and how to integrate it within a `CodeAgent`. #### Generating a tool to generate ideas about the superhero-themed party Alfred's party at the mansion is a **superhero-themed event**, but he needs some creative ideas to make it truly special. As a fantastic host, he wants to surprise the guests with a unique theme. To do this, he can use an agent that generates superhero-themed party ideas based on a given category. This way, Alfred can find the perfect party theme to wow his guests. ```python from smolagents import Tool, CodeAgent, InferenceClientModel class SuperheroPartyThemeTool(Tool): name = "superhero_party_theme_generator" description = """ This tool suggests creative superhero-themed party ideas based on a category. It returns a unique party theme idea.""" inputs = { "category": { "type": "string", "description": "The type of superhero party (e.g., 'classic heroes', 'villain masquerade', 'futuristic Gotham').", } } output_type = "string" def forward(self, category: str): themes = { "classic heroes": "Justice League Gala: Guests come dressed as their favorite DC heroes with themed cocktails like 'The Kryptonite Punch'.", "villain masquerade": "Gotham Rogues' Ball: A mysterious masquerade where guests dress as classic Batman villains.", "futuristic Gotham": "Neo-Gotham Night: A cyberpunk-style party inspired by Batman Beyond, with neon decorations and futuristic gadgets." } return themes.get(category.lower(), "Themed party idea not found. Try 'classic heroes', 'villain masquerade', or 'futuristic Gotham'.") # Instantiate the tool party_theme_tool = SuperheroPartyThemeTool() agent = CodeAgent(tools=[party_theme_tool], model=InferenceClientModel()) # Run the agent to generate a party theme idea result = agent.run( "What would be a good superhero party idea for a 'villain masquerade' theme?" ) print(result) # Output: "Gotham Rogues' Ball: A mysterious masquerade where guests dress as classic Batman villains." ``` With this tool, Alfred will be the ultimate super host, impressing his guests with a superhero-themed party they won't forget! 🦸‍♂️🦸‍♀️ ## Default Toolbox `smolagents` comes with a set of pre-built tools that can be directly injected into your agent. The [default toolbox](https://huggingface.co/docs/smolagents/guided_tour?build-a-tool=Decorate+a+function+with+%40tool#default-toolbox) includes: - **PythonInterpreterTool** - **FinalAnswerTool** - **UserInputTool** - **DuckDuckGoSearchTool** - **GoogleSearchTool** - **VisitWebpageTool** Alfred could use various tools to ensure a flawless party at Wayne Manor: - First, he could use the `DuckDuckGoSearchTool` to find creative superhero-themed party ideas. - For catering, he'd rely on the `GoogleSearchTool` to find the highest-rated services in Gotham. - To manage seating arrangements, Alfred could run calculations with the `PythonInterpreterTool`. - Once everything is gathered, he'd compile the plan using the `FinalAnswerTool`. With these tools, Alfred guarantees the party is both exceptional and seamless. 🦇💡 ## Sharing and Importing Tools One of the most powerful features of **smolagents** is its ability to share custom tools on the Hub and seamlessly integrate tools created by the community. This includes connecting with **HF Spaces** and **LangChain tools**, significantly enhancing Alfred's ability to orchestrate an unforgettable party at Wayne Manor. 🎭 With these integrations, Alfred can tap into advanced event-planning tools—whether it's adjusting the lighting for the perfect ambiance, curating the ideal playlist for the party, or coordinating with Gotham's finest caterers. Here are examples showcasing how these functionalities can elevate the party experience: ### Sharing a Tool to the Hub Sharing your custom tool with the community is easy! Simply upload it to your Hugging Face account using the `push_to_hub()` method. For instance, Alfred can share his `party_theme_tool` to help others find the best catering services in Gotham. Here's how to do it: ```python party_theme_tool.push_to_hub("{your_username}/party_theme_tool", token="") ``` ### Importing a Tool from the Hub You can easily import tools created by other users using the `load_tool()` function. For example, Alfred might want to generate a promotional image for the party using AI. Instead of building a tool from scratch, he can leverage a predefined one from the community: ```python from smolagents import load_tool, CodeAgent, InferenceClientModel image_generation_tool = load_tool( "m-ric/text-to-image", trust_remote_code=True ) agent = CodeAgent( tools=[image_generation_tool], model=InferenceClientModel() ) agent.run("Generate an image of a luxurious superhero-themed party at Wayne Manor with made-up superheros.") ``` ### Importing a Hugging Face Space as a Tool You can also import a HF Space as a tool using `Tool.from_space()`. This opens up possibilities for integrating with thousands of spaces from the community for tasks from image generation to data analysis. The tool will connect with the spaces Gradio backend using the `gradio_client`, so make sure to install it via `pip` if you don't have it already. For the party, Alfred can use an existing HF Space for the generation of the AI-generated image to be used in the announcement (instead of the pre-built tool we mentioned before). Let's build it! ```python from smolagents import CodeAgent, InferenceClientModel, Tool image_generation_tool = Tool.from_space( "black-forest-labs/FLUX.1-schnell", name="image_generator", description="Generate an image from a prompt" ) model = InferenceClientModel("Qwen/Qwen2.5-Coder-32B-Instruct") agent = CodeAgent(tools=[image_generation_tool], model=model) agent.run( "Improve this prompt, then generate an image of it.", additional_args={'user_prompt': 'A grand superhero-themed party at Wayne Manor, with Alfred overseeing a luxurious gala'} ) ``` ### Importing a LangChain Tool We'll discuss the `LangChain` framework in upcoming sections. For now, we just note that we can reuse LangChain tools in your smolagents workflow! You can easily load LangChain tools using the `Tool.from_langchain()` method. Alfred, ever the perfectionist, is preparing for a spectacular superhero night at Wayne Manor while the Waynes are away. To make sure every detail exceeds expectations, he taps into LangChain tools to find top-tier entertainment ideas. By using `Tool.from_langchain()`, Alfred effortlessly adds advanced search functionalities to his smolagent, enabling him to discover exclusive party ideas and services with just a few commands. Here's how he does it: We first need to install the `langchain` integration for `smolagents`. ```bash pip install -U langchain-community ``` After installing the langchain integration, make sure to set your SerpAPI key. This is required for search-based tools such as `SerpAPITool`: ```python os.environ['SERPAPI_API_KEY'] = '...' ``` You can create a SerpAPI key [here](https://serpapi.com/) ```python from langchain.agents import load_tools from smolagents import CodeAgent, InferenceClientModel, Tool search_tool = Tool.from_langchain(load_tools(["serpapi"])[0]) agent = CodeAgent(tools=[search_tool], model=model) agent.run("Search for luxury entertainment ideas for a superhero-themed event, such as live performances and interactive experiences.") ``` ### Importing a tool collection from any MCP server `smolagents` also allows importing tools from the hundreds of MCP servers available on [glama.ai](https://glama.ai/mcp/servers) or [smithery.ai](https://smithery.ai). If you want to dive deeper about MCP, you can check our [free MCP Course](https://huggingface.co/learn/mcp-course/).
Install mcp client We first need to install the `mcp` integration for `smolagents`. ```bash pip install "smolagents[mcp]" ```
The MCP servers tools can be loaded in a ToolCollection object as follow: ```python import os from smolagents import ToolCollection, CodeAgent from mcp import StdioServerParameters from smolagents import InferenceClientModel model = InferenceClientModel("Qwen/Qwen2.5-Coder-32B-Instruct") server_parameters = StdioServerParameters( command="uvx", args=["--quiet", "pubmedmcp@0.1.3"], env={"UV_PYTHON": "3.12", **os.environ}, ) with ToolCollection.from_mcp(server_parameters, trust_remote_code=True) as tool_collection: agent = CodeAgent(tools=[*tool_collection.tools], model=model, add_base_tools=True) agent.run("Please find a remedy for hangover.") ``` With this setup, Alfred can quickly discover luxurious entertainment options, ensuring Gotham's elite guests have an unforgettable experience. This tool helps him curate the perfect superhero-themed event for Wayne Manor! 🎉 ## Resources - [Tools Tutorial](https://huggingface.co/docs/smolagents/tutorials/tools) - Explore this tutorial to learn how to work with tools effectively. - [Tools Documentation](https://huggingface.co/docs/smolagents/v1.8.1/en/reference/tools) - Comprehensive reference documentation on tools. - [Tools Guided Tour](https://huggingface.co/docs/smolagents/v1.8.1/en/guided_tour#tools) - A step-by-step guided tour to help you build and utilize tools efficiently. - [Building Effective Agents](https://huggingface.co/docs/smolagents/tutorials/building_good_agents) - A detailed guide on best practices for developing reliable and high-performance custom function agents. ================================================ FILE: units/en/unit2/smolagents/vision_agents.mdx ================================================ # Vision Agents with smolagents > [!WARNING] > The examples in this section require access to a powerful VLM model. We tested them using the GPT-4o API. > However, Why use smolagents discusses alternative solutions supported by smolagents and Hugging Face. If you'd like to explore other options, be sure to check that section. Empowering agents with visual capabilities is crucial for solving tasks that go beyond text processing. Many real-world challenges, such as web browsing or document understanding, require analyzing rich visual content. Fortunately, `smolagents` provides built-in support for vision-language models (VLMs), enabling agents to process and interpret images effectively. In this example, imagine Alfred, the butler at Wayne Manor, is tasked with verifying the identities of the guests attending the party. As you can imagine, Alfred may not be familiar with everyone arriving. To help him, we can use an agent that verifies their identity by searching for visual information about their appearance using a VLM. This will allow Alfred to make informed decisions about who can enter. Let's build this example! ## Providing Images at the Start of the Agent's Execution > [!TIP] > You can follow the code in this notebook that you can run using Google Colab. In this approach, images are passed to the agent at the start and stored as `task_images` alongside the task prompt. The agent then processes these images throughout its execution. Consider the case where Alfred wants to verify the identities of the superheroes attending the party. He already has a dataset of images from previous parties with the names of the guests. Given a new visitor's image, the agent can compare it with the existing dataset and make a decision about letting them in. In this case, a guest is trying to enter, and Alfred suspects that this visitor might be The Joker impersonating Wonder Woman. Alfred needs to verify their identity to prevent anyone unwanted from entering. Let’s build the example. First, the images are loaded. In this case, we use images from Wikipedia to keep the example minimal, but imagine the possible use-case! ```python from PIL import Image import requests from io import BytesIO image_urls = [ "https://upload.wikimedia.org/wikipedia/commons/e/e8/The_Joker_at_Wax_Museum_Plus.jpg", # Joker image "https://upload.wikimedia.org/wikipedia/en/9/98/Joker_%28DC_Comics_character%29.jpg" # Joker image ] images = [] for url in image_urls: headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" } response = requests.get(url,headers=headers) image = Image.open(BytesIO(response.content)).convert("RGB") images.append(image) ``` Now that we have the images, the agent will tell us whether one guest is actually a superhero (Wonder Woman) or a villain (The Joker). ```python from smolagents import CodeAgent, OpenAIServerModel model = OpenAIServerModel(model_id="gpt-4o") # Instantiate the agent agent = CodeAgent( tools=[], model=model, max_steps=20, verbosity_level=2 ) response = agent.run( """ Describe the costume and makeup that the comic character in these photos is wearing and return the description. Tell me if the guest is The Joker or Wonder Woman. """, images=images ) ``` In the case of my run, the output is the following, although it could vary in your case, as we've already discussed: ```python { 'Costume and Makeup - First Image': ( 'Purple coat and a purple silk-like cravat or tie over a mustard-yellow shirt.', 'White face paint with exaggerated features, dark eyebrows, blue eye makeup, red lips forming a wide smile.' ), 'Costume and Makeup - Second Image': ( 'Dark suit with a flower on the lapel, holding a playing card.', 'Pale skin, green hair, very red lips with an exaggerated grin.' ), 'Character Identity': 'This character resembles known depictions of The Joker from comic book media.' } ``` In this case, the output reveals that the person is impersonating someone else, so we can prevent The Joker from entering the party! ## Providing Images with Dynamic Retrieval > [!TIP] > You can follow the code in this Python file The previous approach is valuable and has many potential use cases. However, in situations where the guest is not in the database, we need to explore other ways of identifying them. One possible solution is to dynamically retrieve images and information from external sources, such as browsing the web for details. In this approach, images are dynamically added to the agent's memory during execution. As we know, agents in `smolagents` are based on the `MultiStepAgent` class, which is an abstraction of the ReAct framework. This class operates in a structured cycle where various variables and knowledge are logged at different stages: 1. **SystemPromptStep:** Stores the system prompt. 2. **TaskStep:** Logs the user query and any provided input. 3. **ActionStep:** Captures logs from the agent's actions and results. This structured approach allows agents to incorporate visual information dynamically and respond adaptively to evolving tasks. Below is the diagram we've already seen, illustrating the dynamic workflow process and how different steps integrate within the agent lifecycle. When browsing, the agent can take screenshots and save them as `observation_images` in the `ActionStep`. ![Dynamic image retrieval](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/smolagents-can-see/diagram_adding_vlms_smolagents.png) Now that we understand the need, let's build our complete example. In this case, Alfred wants full control over the guest verification process, so browsing for details becomes a viable solution. To complete this example, we need a new set of tools for the agent. Additionally, we'll use Selenium and Helium, which are browser automation tools. This will allow us to build an agent that explores the web, searching for details about a potential guest and retrieving verification information. Let's install the tools needed: ```bash pip install "smolagents[all]" helium selenium python-dotenv ``` We'll need a set of agent tools specifically designed for browsing, such as `search_item_ctrl_f`, `go_back`, and `close_popups`. These tools allow the agent to act like a person navigating the web. ```python @tool def search_item_ctrl_f(text: str, nth_result: int = 1) -> str: """ Searches for text on the current page via Ctrl + F and jumps to the nth occurrence. Args: text: The text to search for nth_result: Which occurrence to jump to (default: 1) """ elements = driver.find_elements(By.XPATH, f"//*[contains(text(), '{text}')]") if nth_result > len(elements): raise Exception(f"Match n°{nth_result} not found (only {len(elements)} matches found)") result = f"Found {len(elements)} matches for '{text}'." elem = elements[nth_result - 1] driver.execute_script("arguments[0].scrollIntoView(true);", elem) result += f"Focused on element {nth_result} of {len(elements)}" return result @tool def go_back() -> None: """Goes back to previous page.""" driver.back() @tool def close_popups() -> str: """ Closes any visible modal or pop-up on the page. Use this to dismiss pop-up windows! This does not work on cookie consent banners. """ webdriver.ActionChains(driver).send_keys(Keys.ESCAPE).perform() ``` We also need functionality for saving screenshots, as this will be an essential part of what our VLM agent uses to complete the task. This functionality captures the screenshot and saves it in `step_log.observations_images = [image.copy()]`, allowing the agent to store and process the images dynamically as it navigates. ```python def save_screenshot(step_log: ActionStep, agent: CodeAgent) -> None: sleep(1.0) # Let JavaScript animations happen before taking the screenshot driver = helium.get_driver() current_step = step_log.step_number if driver is not None: for step_logs in agent.logs: # Remove previous screenshots from logs for lean processing if isinstance(step_log, ActionStep) and step_log.step_number <= current_step - 2: step_logs.observations_images = None png_bytes = driver.get_screenshot_as_png() image = Image.open(BytesIO(png_bytes)) print(f"Captured a browser screenshot: {image.size} pixels") step_log.observations_images = [image.copy()] # Create a copy to ensure it persists, important! # Update observations with current URL url_info = f"Current url: {driver.current_url}" step_log.observations = url_info if step_logs.observations is None else step_log.observations + "\n" + url_info return ``` This function is passed to the agent as `step_callback`, as it's triggered at the end of each step during the agent's execution. This allows the agent to dynamically capture and store screenshots throughout its process. Now, we can generate our vision agent for browsing the web, providing it with the tools we created, along with the `DuckDuckGoSearchTool` to explore the web. This tool will help the agent retrieve necessary information for verifying guests' identities based on visual cues. ```python from smolagents import CodeAgent, OpenAIServerModel, DuckDuckGoSearchTool model = OpenAIServerModel(model_id="gpt-4o") agent = CodeAgent( tools=[DuckDuckGoSearchTool(), go_back, close_popups, search_item_ctrl_f], model=model, additional_authorized_imports=["helium"], step_callbacks=[save_screenshot], max_steps=20, verbosity_level=2, ) ``` With that, Alfred is ready to check the guests' identities and make informed decisions about whether to let them into the party: ```python agent.run(""" I am Alfred, the butler of Wayne Manor, responsible for verifying the identity of guests at party. A superhero has arrived at the entrance claiming to be Wonder Woman, but I need to confirm if she is who she says she is. Please search for images of Wonder Woman and generate a detailed visual description based on those images. Additionally, navigate to Wikipedia to gather key details about her appearance. With this information, I can determine whether to grant her access to the event. """ + helium_instructions) ``` You can see that we include `helium_instructions` as part of the task. This special prompt is aimed to control the navigation of the agent, ensuring that it follows the correct steps while browsing the web. Let's see how this works in the video below: This is the final output: ```python Final answer: Wonder Woman is typically depicted wearing a red and gold bustier, blue shorts or skirt with white stars, a golden tiara, silver bracelets, and a golden Lasso of Truth. She is Princess Diana of Themyscira, known as Diana Prince in the world of men. ``` With all of that, we've successfully created our identity verifier for the party! Alfred now has the necessary tools to ensure only the right guests make it through the door. Everything is set to have a good time at Wayne Manor! ## Further Reading - [We just gave sight to smolagents](https://huggingface.co/blog/smolagents-can-see) - Blog describing the vision agent functionality. - [Web Browser Automation with Agents 🤖🌐](https://huggingface.co/docs/smolagents/examples/web_browser) - Example for Web browsing using a vision agent. - [Web Browser Vision Agent Example](https://github.com/huggingface/smolagents/blob/main/src/smolagents/vision_web_browser.py) - Example for Web browsing using a vision agent. ================================================ FILE: units/en/unit2/smolagents/why_use_smolagents.mdx ================================================ ![smolagents banner](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/smolagents/license_to_call.png) # Why use smolagents In this module, we will explore the pros and cons of using [smolagents](https://huggingface.co/docs/smolagents/en/index), helping you make an informed decision about whether it's the right framework for your needs. ## What is `smolagents`? `smolagents` is a simple yet powerful framework for building AI agents. It provides LLMs with the _agency_ to interact with the real world, such as searching or generating images. As we learned in unit 1, AI agents are programs that use LLMs to generate **'thoughts'** based on **'observations'** to perform **'actions'**. Let's explore how this is implemented in smolagents. ### Key Advantages of `smolagents` - **Simplicity:** Minimal code complexity and abstractions, to make the framework easy to understand, adopt and extend - **Flexible LLM Support:** Works with any LLM through integration with Hugging Face tools and external APIs - **Code-First Approach:** First-class support for Code Agents that write their actions directly in code, removing the need for parsing and simplifying tool calling - **HF Hub Integration:** Seamless integration with the Hugging Face Hub, allowing the use of Gradio Spaces as tools ### When to use smolagents? With these advantages in mind, when should we use smolagents over other frameworks? smolagents is ideal when: - You need a **lightweight and minimal solution.** - You want to **experiment quickly** without complex configurations. - Your **application logic is straightforward.** ### Code vs. JSON Actions Unlike other frameworks where agents write actions in JSON, `smolagents` **focuses on tool calls in code**, simplifying the execution process. This is because there's no need to parse the JSON in order to build code that calls the tools: the output can be executed directly. The following diagram illustrates this difference: ![Code vs. JSON actions](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/code_vs_json_actions.png) To review the difference between Code vs JSON Actions, you can revisit [the Actions Section in Unit 1](https://huggingface.co/learn/agents-course/unit1/actions#actions-enabling-the-agent-to-engage-with-its-environment). ### Agent Types in `smolagents` Agents in `smolagents` operate as **multi-step agents**. Each [`MultiStepAgent`](https://huggingface.co/docs/smolagents/main/en/reference/agents#smolagents.MultiStepAgent) performs: - One thought - One tool call and execution In addition to using **[CodeAgent](https://huggingface.co/docs/smolagents/main/en/reference/agents#smolagents.CodeAgent)** as the primary type of agent, smolagents also supports **[ToolCallingAgent](https://huggingface.co/docs/smolagents/main/en/reference/agents#smolagents.ToolCallingAgent)**, which writes tool calls in JSON. We will explore each agent type in more detail in the following sections. > [!TIP] > In smolagents, tools are defined using @tool decorator wrapping a Python function or the Tool class. ### Model Integration in `smolagents` `smolagents` supports flexible LLM integration, allowing you to use any callable model that meets [certain criteria](https://huggingface.co/docs/smolagents/main/en/reference/models). The framework provides several predefined classes to simplify model connections: - **[TransformersModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.TransformersModel):** Implements a local `transformers` pipeline for seamless integration. - **[InferenceClientModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.InferenceClientModel):** Supports [serverless inference](https://huggingface.co/docs/huggingface_hub/main/en/guides/inference) calls through [Hugging Face's infrastructure](https://huggingface.co/docs/api-inference/index), or via a growing number of [third-party inference providers](https://huggingface.co/docs/huggingface_hub/main/en/guides/inference#supported-providers-and-tasks). - **[LiteLLMModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.LiteLLMModel):** Leverages [LiteLLM](https://www.litellm.ai/) for lightweight model interactions. - **[OpenAIServerModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.OpenAIServerModel):** Connects to any service that offers an OpenAI API interface. - **[AzureOpenAIServerModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.AzureOpenAIServerModel):** Supports integration with any Azure OpenAI deployment. This flexibility ensures that developers can choose the model and service most suitable for their specific use cases, and allows for easy experimentation. Now that we understood why and when to use smolagents, let's dive deeper into this powerful library! ## Resources - [smolagents Blog](https://huggingface.co/blog/smolagents) - Introduction to smolagents and code interactions ================================================ FILE: units/en/unit3/README.md ================================================ ================================================ FILE: units/en/unit3/agentic-rag/agent.mdx ================================================ # Creating Your Gala Agent Now that we've built all the necessary components for Alfred, it's time to bring everything together into a complete agent that can help host our extravagant gala. In this section, we'll combine the guest information retrieval, web search, weather information, and Hub stats tools into a single powerful agent. ## Assembling Alfred: The Complete Agent Instead of reimplementing all the tools we've created in previous sections, we'll import them from their respective modules which we saved in the `tools.py` and `retriever.py` files. > [!TIP] > If you haven't implemented the tools yet, go back to the tools and retriever sections to implement them, and add them to the tools.py and retriever.py files. Let's import the necessary libraries and tools from the previous sections: ```python # Import necessary libraries import random from smolagents import CodeAgent, InferenceClientModel # Import our custom tools from their modules from tools import DuckDuckGoSearchTool, WeatherInfoTool, HubStatsTool from retriever import load_guest_dataset ``` Now, let's combine all these tools into a single agent: ```python # Initialize the Hugging Face model model = InferenceClientModel() # Initialize the web search tool search_tool = DuckDuckGoSearchTool() # Initialize the weather tool weather_info_tool = WeatherInfoTool() # Initialize the Hub stats tool hub_stats_tool = HubStatsTool() # Load the guest dataset and initialize the guest info tool guest_info_tool = load_guest_dataset() # Create Alfred with all the tools alfred = CodeAgent( tools=[guest_info_tool, weather_info_tool, hub_stats_tool, search_tool], model=model, add_base_tools=True, # Add any additional base tools planning_interval=3 # Enable planning every 3 steps ) ``` ```python # Import necessary libraries from llama_index.core.agent.workflow import AgentWorkflow from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI from tools import search_tool, weather_info_tool, hub_stats_tool from retriever import guest_info_tool ``` Now, let's combine all these tools into a single agent: ```python # Initialize the Hugging Face model llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") # Create Alfred with all the tools alfred = AgentWorkflow.from_tools_or_functions( [guest_info_tool, search_tool, weather_info_tool, hub_stats_tool], llm=llm, ) ``` ```python from typing import TypedDict, Annotated from langgraph.graph.message import add_messages from langchain_core.messages import AnyMessage, HumanMessage, AIMessage from langgraph.prebuilt import ToolNode from langgraph.graph import START, StateGraph from langgraph.prebuilt import tools_condition from langchain_huggingface import HuggingFaceEndpoint, ChatHuggingFace from tools import DuckDuckGoSearchRun, weather_info_tool, hub_stats_tool from retriever import guest_info_tool ``` Now, let’s combine all these tools into a single agent: ```python # Initialize the web search tool search_tool = DuckDuckGoSearchRun() # Generate the chat interface, including the tools llm = HuggingFaceEndpoint( repo_id="Qwen/Qwen2.5-Coder-32B-Instruct", huggingfacehub_api_token=HUGGINGFACEHUB_API_TOKEN, ) chat = ChatHuggingFace(llm=llm, verbose=True) tools = [guest_info_tool, search_tool, weather_info_tool, hub_stats_tool] chat_with_tools = chat.bind_tools(tools) # Generate the AgentState and Agent graph class AgentState(TypedDict): messages: Annotated[list[AnyMessage], add_messages] def assistant(state: AgentState): return { "messages": [chat_with_tools.invoke(state["messages"])], } ## The graph builder = StateGraph(AgentState) # Define nodes: these do the work builder.add_node("assistant", assistant) builder.add_node("tools", ToolNode(tools)) # Define edges: these determine how the control flow moves builder.add_edge(START, "assistant") builder.add_conditional_edges( "assistant", # If the latest message requires a tool, route to tools # Otherwise, provide a direct response tools_condition, ) builder.add_edge("tools", "assistant") alfred = builder.compile() ``` Your agent is now ready to use! ## Using Alfred: End-to-End Examples Now that Alfred is fully equipped with all the necessary tools, let's see how he can help with various tasks during the gala. ### Example 1: Finding Guest Information Let's see how Alfred can help us with our guest information. ```python query = "Tell me about 'Lady Ada Lovelace'" response = alfred.run(query) print("🎩 Alfred's Response:") print(response) ``` Expected output: ``` 🎩 Alfred's Response: Based on the information I retrieved, Lady Ada Lovelace is an esteemed mathematician and friend. She is renowned for her pioneering work in mathematics and computing, often celebrated as the first computer programmer due to her work on Charles Babbage's Analytical Engine. Her email address is ada.lovelace@example.com. ``` ```python query = "Tell me about Lady Ada Lovelace. What's her background?" response = await alfred.run(query) print("🎩 Alfred's Response:") print(response.response.blocks[0].text) ``` Expected output: ``` 🎩 Alfred's Response: Lady Ada Lovelace was an English mathematician and writer, best known for her work on Charles Babbage's Analytical Engine. She was the first to recognize that the machine had applications beyond pure calculation. ``` ```python response = alfred.invoke({"messages": "Tell me about 'Lady Ada Lovelace'"}) print("🎩 Alfred's Response:") print(response['messages'][-1].content) ``` Expected output: ``` 🎩 Alfred's Response: Ada Lovelace, also known as Augusta Ada King, Countess of Lovelace, was an English mathematician and writer. Born on December 10, 1815, and passing away on November 27, 1852, she is renowned for her work on Charles Babbage's Analytical Engine, a proposed mechanical general-purpose computer. Ada Lovelace is celebrated as one of the first computer programmers because she created a program for the Analytical Engine in 1843. She recognized that the machine could be used for more than mere calculation, envisioning its potential in a way that few did at the time. Her contributions to the field of computer science laid the groundwork for future developments. A day in October, designated as Ada Lovelace Day, honors women's contributions to science and technology, inspired by Lovelace's pioneering work. ``` ### Example 2: Checking the Weather for Fireworks Let's see how Alfred can help us with the weather. ```python query = "What's the weather like in Paris tonight? Will it be suitable for our fireworks display?" response = alfred.run(query) print("🎩 Alfred's Response:") print(response) ``` Expected output (will vary due to randomness): ``` 🎩 Alfred's Response: I've checked the weather in Paris for you. Currently, it's clear with a temperature of 25°C. These conditions are perfect for the fireworks display tonight. The clear skies will provide excellent visibility for the spectacular show, and the comfortable temperature will ensure the guests can enjoy the outdoor event without discomfort. ``` ```python query = "What's the weather like in Paris tonight? Will it be suitable for our fireworks display?" response = await alfred.run(query) print("🎩 Alfred's Response:") print(response) ``` Expected output: ``` 🎩 Alfred's Response: The weather in Paris tonight is rainy with a temperature of 15°C. Given the rain, it may not be suitable for a fireworks display. ``` ```python response = alfred.invoke({"messages": "What's the weather like in Paris tonight? Will it be suitable for our fireworks display?"}) print("🎩 Alfred's Response:") print(response['messages'][-1].content) ``` Expected output: ``` 🎩 Alfred's Response: The weather in Paris tonight is rainy with a temperature of 15°C, which may not be suitable for your fireworks display. ``` ### Example 3: Impressing AI Researchers Let's see how Alfred can help us impress AI researchers. ```python query = "One of our guests is from Qwen. What can you tell me about their most popular model?" response = alfred.run(query) print("🎩 Alfred's Response:") print(response) ``` Expected output: ``` 🎩 Alfred's Response: The most popular Qwen model is Qwen/Qwen2.5-VL-7B-Instruct with 3,313,345 downloads. ``` ```python query = "One of our guests is from Google. What can you tell me about their most popular model?" response = await alfred.run(query) print("🎩 Alfred's Response:") print(response) ``` Expected output: ``` 🎩 Alfred's Response: The most popular model by Google on the Hugging Face Hub is google/electra-base-discriminator, with 28,546,752 downloads. ``` ```python response = alfred.invoke({"messages": "One of our guests is from Qwen. What can you tell me about their most popular model?"}) print("🎩 Alfred's Response:") print(response['messages'][-1].content) ``` Expected output: ``` 🎩 Alfred's Response: The most downloaded model by Qwen is Qwen/Qwen2.5-VL-7B-Instruct with 3,313,345 downloads. ``` ### Example 4: Combining Multiple Tools Let's see how Alfred can help us prepare for a conversation with Dr. Nikola Tesla. ```python query = "I need to speak with Dr. Nikola Tesla about recent advancements in wireless energy. Can you help me prepare for this conversation?" response = alfred.run(query) print("🎩 Alfred's Response:") print(response) ``` Expected output: ``` 🎩 Alfred's Response: I've gathered information to help you prepare for your conversation with Dr. Nikola Tesla. Guest Information: Name: Dr. Nikola Tesla Relation: old friend from university days Description: Dr. Nikola Tesla is an old friend from your university days. He's recently patented a new wireless energy transmission system and would be delighted to discuss it with you. Just remember he's passionate about pigeons, so that might make for good small talk. Email: nikola.tesla@gmail.com Recent Advancements in Wireless Energy: Based on my web search, here are some recent developments in wireless energy transmission: 1. Researchers have made progress in long-range wireless power transmission using focused electromagnetic waves 2. Several companies are developing resonant inductive coupling technologies for consumer electronics 3. There are new applications in electric vehicle charging without physical connections Conversation Starters: 1. "I'd love to hear about your new patent on wireless energy transmission. How does it compare to your original concepts from our university days?" 2. "Have you seen the recent developments in resonant inductive coupling for consumer electronics? What do you think of their approach?" 3. "How are your pigeons doing? I remember your fascination with them." This should give you plenty to discuss with Dr. Tesla while demonstrating your knowledge of his interests and recent developments in his field. ``` ```python query = "I need to speak with Dr. Nikola Tesla about recent advancements in wireless energy. Can you help me prepare for this conversation?" response = await alfred.run(query) print("🎩 Alfred's Response:") print(response) ``` Expected output: ``` 🎩 Alfred's Response: Here are some recent advancements in wireless energy that you might find useful for your conversation with Dr. Nikola Tesla: 1. **Advancements and Challenges in Wireless Power Transfer**: This article discusses the evolution of wireless power transfer (WPT) from conventional wired methods to modern applications, including solar space power stations. It highlights the initial focus on microwave technology and the current demand for WPT due to the rise of electric devices. 2. **Recent Advances in Wireless Energy Transfer Technologies for Body-Interfaced Electronics**: This article explores wireless energy transfer (WET) as a solution for powering body-interfaced electronics without the need for batteries or lead wires. It discusses the advantages and potential applications of WET in this context. 3. **Wireless Power Transfer and Energy Harvesting: Current Status and Future Trends**: This article provides an overview of recent advances in wireless power supply methods, including energy harvesting and wireless power transfer. It presents several promising applications and discusses future trends in the field. 4. **Wireless Power Transfer: Applications, Challenges, Barriers, and the ``` ```python response = alfred.invoke({"messages":"I need to speak with 'Dr. Nikola Tesla' about recent advancements in wireless energy. Can you help me prepare for this conversation?"}) print("🎩 Alfred's Response:") print(response['messages'][-1].content) ``` Expected output: ``` Based on the provided information, here are key points to prepare for the conversation with 'Dr. Nikola Tesla' about recent advancements in wireless energy:\n1. **Wireless Power Transmission (WPT):** Discuss how WPT revolutionizes energy transfer by eliminating the need for cords and leveraging mechanisms like inductive and resonant coupling.\n2. **Advancements in Wireless Charging:** Highlight improvements in efficiency, faster charging speeds, and the rise of Qi/Qi2 certified wireless charging solutions.\n3. **5G-Advanced Innovations and NearLink Wireless Protocol:** Mention these as developments that enhance speed, security, and efficiency in wireless networks, which can support advanced wireless energy technologies.\n4. **AI and ML at the Edge:** Talk about how AI and machine learning will rely on wireless networks to bring intelligence to the edge, enhancing automation and intelligence in smart homes and buildings.\n5. **Matter, Thread, and Security Advancements:** Discuss these as key innovations that drive connectivity, efficiency, and security in IoT devices and systems.\n6. **Breakthroughs in Wireless Charging Technology:** Include any recent breakthroughs or studies, such as the one from Incheon National University, to substantiate the advancements in wireless charging. ``` ## Advanced Features: Conversation Memory To make Alfred even more helpful during the gala, we can enable conversation memory so he remembers previous interactions: ```python # Create Alfred with conversation memory alfred_with_memory = CodeAgent( tools=[guest_info_tool, weather_info_tool, hub_stats_tool, search_tool], model=model, add_base_tools=True, planning_interval=3 ) # First interaction response1 = alfred_with_memory.run("Tell me about Lady Ada Lovelace.") print("🎩 Alfred's First Response:") print(response1) # Second interaction (referencing the first) response2 = alfred_with_memory.run("What projects is she currently working on?", reset=False) print("🎩 Alfred's Second Response:") print(response2) ``` ```python from llama_index.core.workflow import Context alfred = AgentWorkflow.from_tools_or_functions( [guest_info_tool, search_tool, weather_info_tool, hub_stats_tool], llm=llm ) # Remembering state ctx = Context(alfred) # First interaction response1 = await alfred.run("Tell me about Lady Ada Lovelace.", ctx=ctx) print("🎩 Alfred's First Response:") print(response1) # Second interaction (referencing the first) response2 = await alfred.run("What projects is she currently working on?", ctx=ctx) print("🎩 Alfred's Second Response:") print(response2) ``` ```python # First interaction response = alfred.invoke({"messages": [HumanMessage(content="Tell me about 'Lady Ada Lovelace'. What's her background and how is she related to me?")]}) print("🎩 Alfred's Response:") print(response['messages'][-1].content) print() # Second interaction (referencing the first) response = alfred.invoke({"messages": response["messages"] + [HumanMessage(content="What projects is she currently working on?")]}) print("🎩 Alfred's Response:") print(response['messages'][-1].content) ``` Notice that none of these three agent approaches directly couple memory with the agent. Is there a specific reason for this design choice 🧐? * smolagents: Memory is not preserved across different execution runs, you must explicitly state it using `reset=False`. * LlamaIndex: Requires explicitly adding a context object for memory management within a run. * LangGraph: Offers options to retrieve previous messages or utilize a dedicated [MemorySaver](https://langchain-ai.github.io/langgraph/tutorials/introduction/#part-3-adding-memory-to-the-chatbot) component. ## Conclusion Congratulations! You've successfully built Alfred, a sophisticated agent equipped with multiple tools to help host the most extravagant gala of the century. Alfred can now: 1. Retrieve detailed information about guests 2. Check weather conditions for planning outdoor activities 3. Provide insights about influential AI builders and their models 4. Search the web for the latest information 5. Maintain conversation context with memory With these capabilities, Alfred is ready to ensure your gala is a resounding success, impressing guests with personalized attention and up-to-date information. ================================================ FILE: units/en/unit3/agentic-rag/agentic-rag.mdx ================================================ # Agentic Retrieval Augmented Generation (RAG) In this unit, we'll be taking a look at how we can use Agentic RAG to help Alfred prepare for the amazing gala. > [!TIP] > We know we've already discussed Retrieval Augmented Generation (RAG) and agentic RAG in the previous unit, so feel free to skip ahead if you're already familiar with the concepts. LLMs are trained on enormous bodies of data to learn general knowledge. However, the world knowledge model of LLMs may not always be relevant and up-to-date information. **RAG solves this problem by finding and retrieving relevant information from your data and forwarding that to the LLM.** ![RAG](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/rag.png) Now, think about how Alfred works: 1. We've asked Alfred to help plan a gala 2. Alfred needs to find the latest news and weather information 3. Alfred needs to structure and search the guest information Just as Alfred needs to search through your household information to be helpful, any agent needs a way to find and understand relevant data. **Agentic RAG is a powerful way to use agents to answer questions about your data.** We can pass various tools to Alfred to help him answer questions. However, instead of answering the question on top of documents automatically, Alfred can decide to use any other tool or flow to answer the question. ![Agentic RAG](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/agentic-rag.png) Let's start **building our agentic RAG workflow!** First, we'll create a RAG tool to retrieve up-to-date details about the invitees. Next, we'll develop tools for web search, weather updates, and Hugging Face Hub model download statistics. Finally, we'll integrate everything to bring our agentic RAG agent to life! ================================================ FILE: units/en/unit3/agentic-rag/conclusion.mdx ================================================ # Conclusion In this unit, we've learned how to create an agentic RAG system to help Alfred, our friendly neighborhood agent, prepare for and manage an extravagant gala. The combination of RAG with agentic capabilities demonstrates how powerful AI assistants can become when they have: - Access to structured knowledge (guest information) - Ability to retrieve real-time information (web search) - Domain-specific tools (weather information, Hub stats) - Memory of past interactions With these capabilities, Alfred is now well-equipped to be the perfect host, able to answer questions about guests, provide up-to-date information, and ensure the gala runs smoothly—even managing the perfect timing for the fireworks display! > [!TIP] > Now that you've built a complete agent, you might want to explore: > > - Creating more specialized tools for your own use cases > - Implementing more sophisticated RAG systems with embeddings > - Building multi-agent systems where agents can collaborate > - Deploying your agent as a service that others can interact with ================================================ FILE: units/en/unit3/agentic-rag/introduction.mdx ================================================ # Introduction to Use Case for Agentic RAG ![Agentic RAG banner](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit3/agentic-rag/thumbnail.jpg) In this unit, we will help Alfred, our friendly agent who is hosting the gala, by using Agentic RAG to create a tool that can be used to answer questions about the guests at the gala. > [!TIP] > This is a 'real-world' use case for Agentic RAG, that you could use in your own projects or workplaces. If you want to get more out of this project, why not try it out on your own use case and share in Discord? You can choose any of the frameworks discussed in the course for this use case. We provide code samples for each in separate tabs. ## A Gala to Remember Now, it's time to get our hands dirty with an actual use case. Let's set the stage! **You decided to host the most extravagant and opulent party of the century.** This means lavish feasts, enchanting dancers, renowned DJs, exquisite drinks, a breathtaking fireworks display, and much more. Alfred, your friendly neighbourhood agent, is getting ready to watch over all of your needs for this party, and **Alfred is going to manage everything himself**. To do so, he needs to have access to all of the information about the party, including the menu, the guests, the schedule, weather forecasts, and much more! Not only that, but he also needs to make sure that the party is going to be a success, so **he needs to be able to answer any questions about the party during the party**, whilst handling unexpected situations that may arise. He can't do this alone, so we need to make sure that Alfred has access to all of the information and tools he needs. First, let's give him a list of hard requirements for the gala. ## The Gala Requirements A properly educated person in the age of the **Renaissance** needs to have three main traits. He or she needed to be profound in the **knowledge of sports, culture, and science**. So, we need to make sure we can impress our guests with our knowledge and provide them with a truly unforgettable gala. However, to avoid any conflicts, there are some **topics, like politics and religion, that are to be avoided at a gala.** It needs to be a fun party without conflicts related to beliefs and ideals. According to etiquette, **a good host should be aware of guests' backgrounds**, including their interests and endeavours. A good host also gossips and shares stories about the guests with one another. Lastly, we need to make sure that we've got **some general knowledge about the weather** to ensure we can continuously find a real-time update to ensure perfect timing to launch the fireworks and end the gala with a bang! 🎆 As you can see, Alfred needs a lot of information to host the gala. Luckily, we can help and prepare Alfred by giving him some **Retrieval Augmented Generation (RAG) training!** Let's start by creating the tools that Alfred needs to be able to host the gala! ================================================ FILE: units/en/unit3/agentic-rag/invitees.mdx ================================================ # Creating a RAG Tool for Guest Stories Alfred, your trusted agent, is preparing for the most extravagant gala of the century. To ensure the event runs smoothly, Alfred needs quick access to up-to-date information about each guest. Let's help Alfred by creating a custom Retrieval-Augmented Generation (RAG) tool, powered by our custom dataset. ## Why RAG for a Gala? Imagine Alfred mingling among the guests, needing to recall specific details about each person at a moment's notice. A traditional LLM might struggle with this task because: 1. The guest list is specific to your event and not in the model's training data 2. Guest information may change or be updated frequently 3. Alfred needs to retrieve precise details like email addresses This is where Retrieval Augmented Generation (RAG) shines! By combining a retrieval system with an LLM, Alfred can access accurate, up-to-date information about your guests on demand. > [!TIP] > You can choose any of the frameworks covered in the course for this use case. Select your preferred option from the code tabs. ## Setting up our application In this unit, we'll develop our agent within a HF Space, as a structured Python project. This approach helps us maintain clean, modular code by organizing different functionalities into separate files. Also, this makes for a more realistic use case where you would deploy the application for public use. ### Project Structure - **`tools.py`** – Provides auxiliary tools for the agent. - **`retriever.py`** – Implements retrieval functions to support knowledge access. - **`app.py`** – Integrates all components into a fully functional agent, which we'll finalize in the last part of this unit. For a hands-on reference, check out [this HF Space](https://huggingface.co/spaces/agents-course/Unit_3_Agentic_RAG), where the Agentic RAG developed in this unit is live. Feel free to clone it and experiment! You can directly test the agent below: ## Dataset Overview Our dataset [`agents-course/unit3-invitees`](https://huggingface.co/datasets/agents-course/unit3-invitees/) contains the following fields for each guest: - **Name**: Guest's full name - **Relation**: How the guest is related to the host - **Description**: A brief biography or interesting facts about the guest - **Email Address**: Contact information for sending invitations or follow-ups Below is a preview of the dataset: > [!TIP] > In a real-world scenario, this dataset could be expanded to include dietary preferences, gift interests, conversation topics to avoid, and other helpful details for a host. ## Building the Guestbook Tool We'll create a custom tool that Alfred can use to quickly retrieve guest information during the gala. Let's break this down into three manageable steps: 1. Load and prepare the dataset 2. Create the Retriever Tool 3. Integrate the Tool with Alfred Let's start with loading and preparing the dataset! ### Step 1: Load and Prepare the Dataset First, we need to transform our raw guest data into a format that's optimized for retrieval. We will use the Hugging Face `datasets` library to load the dataset and convert it into a list of `Document` objects from the `langchain.docstore.document` module. ```python import datasets from langchain_core.documents import Document # Load the dataset guest_dataset = datasets.load_dataset("agents-course/unit3-invitees", split="train") # Convert dataset entries into Document objects docs = [ Document( page_content="\n".join([ f"Name: {guest['name']}", f"Relation: {guest['relation']}", f"Description: {guest['description']}", f"Email: {guest['email']}" ]), metadata={"name": guest["name"]} ) for guest in guest_dataset ] ``` We will use the Hugging Face `datasets` library to load the dataset and convert it into a list of `Document` objects from the `llama_index.core.schema` module. ```python import datasets from llama_index.core.schema import Document # Load the dataset guest_dataset = datasets.load_dataset("agents-course/unit3-invitees", split="train") # Convert dataset entries into Document objects docs = [ Document( text="\n".join([ f"Name: {guest_dataset['name'][i]}", f"Relation: {guest_dataset['relation'][i]}", f"Description: {guest_dataset['description'][i]}", f"Email: {guest_dataset['email'][i]}" ]), metadata={"name": guest_dataset['name'][i]} ) for i in range(len(guest_dataset)) ] ``` We will use the Hugging Face `datasets` library to load the dataset and convert it into a list of `Document` objects from the `langchain.docstore.document` module. ```python import datasets from langchain_core.documents import Document # Load the dataset guest_dataset = datasets.load_dataset("agents-course/unit3-invitees", split="train") # Convert dataset entries into Document objects docs = [ Document( page_content="\n".join([ f"Name: {guest['name']}", f"Relation: {guest['relation']}", f"Description: {guest['description']}", f"Email: {guest['email']}" ]), metadata={"name": guest["name"]} ) for guest in guest_dataset ] ``` In the code above, we: - Load the dataset - Convert each guest entry into a `Document` object with formatted content - Store the `Document` objects in a list This means we've got all of our data nicely available so we can get started with configuring our retrieval. ### Step 2: Create the Retriever Tool Now, let's create a custom tool that Alfred can use to search through our guest information. We will use the `BM25Retriever` from the `langchain_community.retrievers` module to create a retriever tool. > [!TIP] > The BM25Retriever is a great starting point for retrieval, but for more advanced semantic search, you might consider using embedding-based retrievers like those from sentence-transformers. ```python from smolagents import Tool from langchain_community.retrievers import BM25Retriever class GuestInfoRetrieverTool(Tool): name = "guest_info_retriever" description = "Retrieves detailed information about gala guests based on their name or relation." inputs = { "query": { "type": "string", "description": "The name or relation of the guest you want information about." } } output_type = "string" def __init__(self, docs): self.is_initialized = False self.retriever = BM25Retriever.from_documents(docs) def forward(self, query: str): results = self.retriever.invoke(query) if results: return "\n\n".join([doc.page_content for doc in results[:3]]) else: return "No matching guest information found." # Initialize the tool guest_info_tool = GuestInfoRetrieverTool(docs) ``` Let's understand this tool step-by-step: - The `name` and `description` help the agent understand when and how to use this tool - The `inputs` define what parameters the tool expects (in this case, a search query) - We're using a `BM25Retriever`, which is a powerful text retrieval algorithm that doesn't require embeddings - The `forward` method processes the query and returns the most relevant guest information We will use the `BM25Retriever` from the `llama_index.retrievers.bm25` module to create a retriever tool. > [!TIP] > The BM25Retriever is a great starting point for retrieval, but for more advanced semantic search, you might consider using embedding-based retrievers like those from sentence-transformers. ```python from llama_index.core.tools import FunctionTool from llama_index.retrievers.bm25 import BM25Retriever bm25_retriever = BM25Retriever.from_defaults(nodes=docs) def get_guest_info_retriever(query: str) -> str: """Retrieves detailed information about gala guests based on their name or relation.""" results = bm25_retriever.retrieve(query) if results: return "\n\n".join([doc.text for doc in results[:3]]) else: return "No matching guest information found." # Initialize the tool guest_info_tool = FunctionTool.from_defaults(get_guest_info_retriever) ``` Let's understand this tool step-by-step. - The docstring helps the agent understand when and how to use this tool - The type decorators define what parameters the tool expects (in this case, a search query) - We're using a `BM25Retriever`, which is a powerful text retrieval algorithm that doesn't require embeddings - The method processes the query and returns the most relevant guest information We will use the `BM25Retriever` from the `langchain_community.retrievers` module to create a retriever tool. > [!TIP] > The BM25Retriever is a great starting point for retrieval, but for more advanced semantic search, you might consider using embedding-based retrievers like those from sentence-transformers. ```python from langchain_community.retrievers import BM25Retriever from langchain_core.tools import Tool bm25_retriever = BM25Retriever.from_documents(docs) def extract_text(query: str) -> str: """Retrieves detailed information about gala guests based on their name or relation.""" results = bm25_retriever.invoke(query) if results: return "\n\n".join([doc.page_content for doc in results[:3]]) else: return "No matching guest information found." guest_info_tool = Tool( name="guest_info_retriever", func=extract_text, description="Retrieves detailed information about gala guests based on their name or relation." ) ``` Let's understand this tool step-by-step. - The `name` and `description` help the agent understand when and how to use this tool - The type decorators define what parameters the tool expects (in this case, a search query) - We're using a `BM25Retriever`, which is a powerful text retrieval algorithm that doesn't require embeddings - The method processes the query and returns the most relevant guest information ### Step 3: Integrate the Tool with Alfred Finally, let's bring everything together by creating our agent and equipping it with our custom tool: ```python from smolagents import CodeAgent, InferenceClientModel # Initialize the Hugging Face model model = InferenceClientModel() # Create Alfred, our gala agent, with the guest info tool alfred = CodeAgent(tools=[guest_info_tool], model=model) # Example query Alfred might receive during the gala response = alfred.run("Tell me about our guest named 'Lady Ada Lovelace'.") print("🎩 Alfred's Response:") print(response) ``` Expected output: ``` 🎩 Alfred's Response: Based on the information I retrieved, Lady Ada Lovelace is an esteemed mathematician and friend. She is renowned for her pioneering work in mathematics and computing, often celebrated as the first computer programmer due to her work on Charles Babbage's Analytical Engine. Her email address is ada.lovelace@example.com. ``` What's happening in this final step: - We initialize a Hugging Face model using the `InferenceClientModel` class - We create our agent (Alfred) as a `CodeAgent`, which can execute Python code to solve problems - We ask Alfred to retrieve information about a guest named "Lady Ada Lovelace" ```python from llama_index.core.agent.workflow import AgentWorkflow from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI # Initialize the Hugging Face model llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") # Create Alfred, our gala agent, with the guest info tool alfred = AgentWorkflow.from_tools_or_functions( [guest_info_tool], llm=llm, ) # Example query Alfred might receive during the gala response = await alfred.run("Tell me about our guest named 'Lady Ada Lovelace'.") print("🎩 Alfred's Response:") print(response) ``` Expected output: ``` 🎩 Alfred's Response: Lady Ada Lovelace is an esteemed mathematician and friend, renowned for her pioneering work in mathematics and computing. She is celebrated as the first computer programmer due to her work on Charles Babbage's Analytical Engine. Her email is ada.lovelace@example.com. ``` What's happening in this final step: - We initialize a Hugging Face model using the `HuggingFaceInferenceAPI` class - We create our agent (Alfred) as a `AgentWorkflow`, including the tool we just created - We ask Alfred to retrieve information about a guest named "Lady Ada Lovelace" ```python from typing import TypedDict, Annotated from langgraph.graph.message import add_messages from langchain_core.messages import AnyMessage, HumanMessage, AIMessage from langgraph.prebuilt import ToolNode from langgraph.graph import START, StateGraph from langgraph.prebuilt import tools_condition from langchain_huggingface import HuggingFaceEndpoint, ChatHuggingFace # Generate the chat interface, including the tools llm = HuggingFaceEndpoint( repo_id="Qwen/Qwen2.5-Coder-32B-Instruct", huggingfacehub_api_token=HUGGINGFACEHUB_API_TOKEN, ) chat = ChatHuggingFace(llm=llm, verbose=True) tools = [guest_info_tool] chat_with_tools = chat.bind_tools(tools) # Generate the AgentState and Agent graph class AgentState(TypedDict): messages: Annotated[list[AnyMessage], add_messages] def assistant(state: AgentState): return { "messages": [chat_with_tools.invoke(state["messages"])], } ## The graph builder = StateGraph(AgentState) # Define nodes: these do the work builder.add_node("assistant", assistant) builder.add_node("tools", ToolNode(tools)) # Define edges: these determine how the control flow moves builder.add_edge(START, "assistant") builder.add_conditional_edges( "assistant", # If the latest message requires a tool, route to tools # Otherwise, provide a direct response tools_condition, ) builder.add_edge("tools", "assistant") alfred = builder.compile() messages = [HumanMessage(content="Tell me about our guest named 'Lady Ada Lovelace'.")] response = alfred.invoke({"messages": messages}) print("🎩 Alfred's Response:") print(response['messages'][-1].content) ``` Expected output: ``` 🎩 Alfred's Response: Lady Ada Lovelace is an esteemed mathematician and pioneer in computing, often celebrated as the first computer programmer due to her work on Charles Babbage's Analytical Engine. ``` What's happening in this final step: - We initialize a Hugging Face model using the `HuggingFaceEndpoint` class. We also generate a chat interface and append the tools. - We create our agent (Alfred) as a `StateGraph`, that combines 2 nodes (`assistant`, `tools`) using an edge - We ask Alfred to retrieve information about a guest named "Lady Ada Lovelace" ## Example Interaction During the gala, a conversation might flow like this: **You:** "Alfred, who is that gentleman talking to the ambassador?" **Alfred:** *quickly searches the guest database* "That's Dr. Nikola Tesla, sir. He's an old friend from your university days. He's recently patented a new wireless energy transmission system and would be delighted to discuss it with you. Just remember he's passionate about pigeons, so that might make for good small talk." ```json { "name": "Dr. Nikola Tesla", "relation": "old friend from university days", "description": "Dr. Nikola Tesla is an old friend from your university days. He's recently patented a new wireless energy transmission system and would be delighted to discuss it with you. Just remember he's passionate about pigeons, so that might make for good small talk.", "email": "nikola.tesla@gmail.com" } ``` ## Taking It Further Now that Alfred can retrieve guest information, consider how you might enhance this system: 1. **Improve the retriever** to use a more sophisticated algorithm like [sentence-transformers](https://www.sbert.net/) 2. **Implement a conversation memory** so Alfred remembers previous interactions 3. **Combine with web search** to get the latest information on unfamiliar guests 4. **Integrate multiple indexes** to get more complete information from verified sources Now Alfred is fully equipped to handle guest inquiries effortlessly, ensuring your gala is remembered as the most sophisticated and delightful event of the century! > [!TIP] > Try extending the retriever tool to also return conversation starters based on each guest's interests or background. How would you modify the tool to accomplish this? > > When you're done, implement your guest retriever tool in the retriever.py file. ================================================ FILE: units/en/unit3/agentic-rag/tools.mdx ================================================ # Building and Integrating Tools for Your Agent In this section, we'll grant Alfred access to the web, enabling him to find the latest news and global updates. Additionally, he'll have access to weather data and Hugging Face hub model download statistics, so that he can make relevant conversation about fresh topics. ## Give Your Agent Access to the Web Remember that we want Alfred to establish his presence as a true renaissance host, with a deep knowledge of the world. To do so, we need to make sure that Alfred has access to the latest news and information about the world. Let's start by creating a web search tool for Alfred! ```python from smolagents import DuckDuckGoSearchTool # Initialize the DuckDuckGo search tool search_tool = DuckDuckGoSearchTool() # Example usage results = search_tool("Who's the current President of France?") print(results) ``` Expected output: ``` The current President of France in Emmanuel Macron. ``` ```python from llama_index.tools.duckduckgo import DuckDuckGoSearchToolSpec from llama_index.core.tools import FunctionTool # Initialize the DuckDuckGo search tool tool_spec = DuckDuckGoSearchToolSpec() search_tool = FunctionTool.from_defaults(tool_spec.duckduckgo_full_search) # Example usage response = search_tool("Who's the current President of France?") print(response.raw_output[-1]['body']) ``` Expected output: ``` The President of the French Republic is the head of state of France. The current President is Emmanuel Macron since 14 May 2017 defeating Marine Le Pen in the second round of the presidential election on 7 May 2017. List of French presidents (Fifth Republic) N° Portrait Name ... ``` ```python from langchain_community.tools import DuckDuckGoSearchRun search_tool = DuckDuckGoSearchRun() results = search_tool.invoke("Who's the current President of France?") print(results) ``` Expected output: ``` Emmanuel Macron (born December 21, 1977, Amiens, France) is a French banker and politician who was elected president of France in 2017... ``` ## Creating a Custom Tool for Weather Information to Schedule the Fireworks The perfect gala would have fireworks over a clear sky, we need to make sure the fireworks are not cancelled due to bad weather. Let's create a custom tool that can be used to call an external weather API and get the weather information for a given location. > [!TIP] > For the sake of simplicity, we're using a dummy weather API for this example. If you want to use a real weather API, you could implement a weather tool that uses the OpenWeatherMap API, like in Unit 1. ```python from smolagents import Tool import random class WeatherInfoTool(Tool): name = "weather_info" description = "Fetches dummy weather information for a given location." inputs = { "location": { "type": "string", "description": "The location to get weather information for." } } output_type = "string" def forward(self, location: str): # Dummy weather data weather_conditions = [ {"condition": "Rainy", "temp_c": 15}, {"condition": "Clear", "temp_c": 25}, {"condition": "Windy", "temp_c": 20} ] # Randomly select a weather condition data = random.choice(weather_conditions) return f"Weather in {location}: {data['condition']}, {data['temp_c']}°C" # Initialize the tool weather_info_tool = WeatherInfoTool() ``` ```python import random from llama_index.core.tools import FunctionTool def get_weather_info(location: str) -> str: """Fetches dummy weather information for a given location.""" # Dummy weather data weather_conditions = [ {"condition": "Rainy", "temp_c": 15}, {"condition": "Clear", "temp_c": 25}, {"condition": "Windy", "temp_c": 20} ] # Randomly select a weather condition data = random.choice(weather_conditions) return f"Weather in {location}: {data['condition']}, {data['temp_c']}°C" # Initialize the tool weather_info_tool = FunctionTool.from_defaults(get_weather_info) ``` ```python from langchain_core.tools import Tool import random def get_weather_info(location: str) -> str: """Fetches dummy weather information for a given location.""" # Dummy weather data weather_conditions = [ {"condition": "Rainy", "temp_c": 15}, {"condition": "Clear", "temp_c": 25}, {"condition": "Windy", "temp_c": 20} ] # Randomly select a weather condition data = random.choice(weather_conditions) return f"Weather in {location}: {data['condition']}, {data['temp_c']}°C" # Initialize the tool weather_info_tool = Tool( name="get_weather_info", func=get_weather_info, description="Fetches dummy weather information for a given location." ) ``` ## Creating a Hub Stats Tool for Influential AI Builders In attendance at the gala are the who's who of AI builders. Alfred wants to impress them by discussing their most popular models, datasets, and spaces. We'll create a tool to fetch model statistics from the Hugging Face Hub based on a username. ```python from smolagents import Tool from huggingface_hub import list_models class HubStatsTool(Tool): name = "hub_stats" description = "Fetches the most downloaded model from a specific author on the Hugging Face Hub." inputs = { "author": { "type": "string", "description": "The username of the model author/organization to find models from." } } output_type = "string" def forward(self, author: str): try: # List models from the specified author, sorted by downloads models = list(list_models(author=author, sort="downloads", direction=-1, limit=1)) if models: model = models[0] return f"The most downloaded model by {author} is {model.id} with {model.downloads:,} downloads." else: return f"No models found for author {author}." except Exception as e: return f"Error fetching models for {author}: {str(e)}" # Initialize the tool hub_stats_tool = HubStatsTool() # Example usage print(hub_stats_tool("facebook")) # Example: Get the most downloaded model by Facebook ``` Expected output: ``` The most downloaded model by facebook is facebook/esmfold_v1 with 12,544,550 downloads. ``` ```python import random from llama_index.core.tools import FunctionTool from huggingface_hub import list_models def get_hub_stats(author: str) -> str: """Fetches the most downloaded model from a specific author on the Hugging Face Hub.""" try: # List models from the specified author, sorted by downloads models = list(list_models(author=author, sort="downloads", direction=-1, limit=1)) if models: model = models[0] return f"The most downloaded model by {author} is {model.id} with {model.downloads:,} downloads." else: return f"No models found for author {author}." except Exception as e: return f"Error fetching models for {author}: {str(e)}" # Initialize the tool hub_stats_tool = FunctionTool.from_defaults(get_hub_stats) # Example usage print(hub_stats_tool("facebook")) # Example: Get the most downloaded model by Facebook ``` Expected output: ``` The most downloaded model by facebook is facebook/esmfold_v1 with 12,544,550 downloads. ``` ```python from langchain_core.tools import Tool from huggingface_hub import list_models def get_hub_stats(author: str) -> str: """Fetches the most downloaded model from a specific author on the Hugging Face Hub.""" try: # List models from the specified author, sorted by downloads models = list(list_models(author=author, sort="downloads", direction=-1, limit=1)) if models: model = models[0] return f"The most downloaded model by {author} is {model.id} with {model.downloads:,} downloads." else: return f"No models found for author {author}." except Exception as e: return f"Error fetching models for {author}: {str(e)}" # Initialize the tool hub_stats_tool = Tool( name="get_hub_stats", func=get_hub_stats, description="Fetches the most downloaded model from a specific author on the Hugging Face Hub." ) # Example usage print(hub_stats_tool.invoke("facebook")) # Example: Get the most downloaded model by Facebook ``` Expected output: ``` The most downloaded model by facebook is facebook/esmfold_v1 with 13,109,861 downloads. ``` With the Hub Stats Tool, Alfred can now impress influential AI builders by discussing their most popular models. ## Integrating Tools with Alfred Now that we have all the tools, let's integrate them into Alfred's agent: ```python from smolagents import CodeAgent, InferenceClientModel # Initialize the Hugging Face model model = InferenceClientModel() # Create Alfred with all the tools alfred = CodeAgent( tools=[search_tool, weather_info_tool, hub_stats_tool], model=model ) # Example query Alfred might receive during the gala response = alfred.run("What is Facebook and what's their most popular model?") print("🎩 Alfred's Response:") print(response) ``` Expected output: ``` 🎩 Alfred's Response: Facebook is a social networking website where users can connect, share information, and interact with others. The most downloaded model by Facebook on the Hugging Face Hub is ESMFold_v1. ``` ```python from llama_index.core.agent.workflow import AgentWorkflow from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI # Initialize the Hugging Face model llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") # Create Alfred with all the tools alfred = AgentWorkflow.from_tools_or_functions( [search_tool, weather_info_tool, hub_stats_tool], llm=llm ) # Example query Alfred might receive during the gala response = await alfred.run("What is Facebook and what's their most popular model?") print("🎩 Alfred's Response:") print(response) ``` Expected output: ``` 🎩 Alfred's Response: Facebook is a social networking service and technology company based in Menlo Park, California. It was founded by Mark Zuckerberg and allows people to create profiles, connect with friends and family, share photos and videos, and join groups based on shared interests. The most popular model by Facebook on the Hugging Face Hub is `facebook/esmfold_v1` with 13,109,861 downloads. ``` ```python from typing import TypedDict, Annotated from langgraph.graph.message import add_messages from langchain_core.messages import AnyMessage, HumanMessage, AIMessage from langgraph.prebuilt import ToolNode from langgraph.graph import START, StateGraph from langgraph.prebuilt import tools_condition from langchain_huggingface import HuggingFaceEndpoint, ChatHuggingFace # Generate the chat interface, including the tools llm = HuggingFaceEndpoint( repo_id="Qwen/Qwen2.5-Coder-32B-Instruct", huggingfacehub_api_token=HUGGINGFACEHUB_API_TOKEN, ) chat = ChatHuggingFace(llm=llm, verbose=True) tools = [search_tool, weather_info_tool, hub_stats_tool] chat_with_tools = chat.bind_tools(tools) # Generate the AgentState and Agent graph class AgentState(TypedDict): messages: Annotated[list[AnyMessage], add_messages] def assistant(state: AgentState): return { "messages": [chat_with_tools.invoke(state["messages"])], } ## The graph builder = StateGraph(AgentState) # Define nodes: these do the work builder.add_node("assistant", assistant) builder.add_node("tools", ToolNode(tools)) # Define edges: these determine how the control flow moves builder.add_edge(START, "assistant") builder.add_conditional_edges( "assistant", # If the latest message requires a tool, route to tools # Otherwise, provide a direct response tools_condition, ) builder.add_edge("tools", "assistant") alfred = builder.compile() messages = [HumanMessage(content="Who is Facebook and what's their most popular model?")] response = alfred.invoke({"messages": messages}) print("🎩 Alfred's Response:") print(response['messages'][-1].content) ``` Expected output: ``` 🎩 Alfred's Response: Facebook is a social media company known for its social networking site, Facebook, as well as other services like Instagram and WhatsApp. The most downloaded model by Facebook on the Hugging Face Hub is facebook/esmfold_v1 with 13,202,321 downloads. ``` ## Conclusion By integrating these tools, Alfred is now equipped to handle a variety of tasks, from web searches to weather updates and model statistics. This ensures he remains the most informed and engaging host at the gala. > [!TIP] > Try implementing a tool that can be used to get the latest news about a specific topic. > > When you're done, implement your custom tools in the tools.py file. ================================================ FILE: units/en/unit4/additional-readings.mdx ================================================ # And now? What topics I should learn? Agentic AI is a rapidly evolving field, and understanding foundational protocols is essential for building intelligent, autonomous systems. Two important standards you should get familiar with are: - The **Model Context Protocol (MCP)** - The **Agent-to-Agent Protocol (A2A)** ## 🔌 Model Context Protocol (MCP) The **Model Context Protocol (MCP)** by Anthropic is an open standard that enables AI models to securely and seamlessly **connect with external tools, data sources, and applications**, making agents more capable and autonomous. Think of MCP as a **universal adapter**, like a USB-C port, that allows AI models to plug into various digital environments **without needing custom integration for each one**. MCP is quickly gaining traction across the industry, with major companies like OpenAI and Google beginning to adopt it. 📚 Learn more: - [Anthropic's official announcement and documentation](https://www.anthropic.com/news/model-context-protocol) - [MCP on Wikipedia](https://en.wikipedia.org/wiki/Model_Context_Protocol) - [Blog on MCP](https://huggingface.co/blog/Kseniase/mcp) ## 🤝 Agent-to-Agent (A2A) Protocol Google has developed the **Agent-to-Agent (A2A) protocol** as a complementary counterpart to Anthropic's Model Context Protocol (MCP). While MCP connects agents to external tools, **A2A connects agents to each other**, paving the way for cooperative, multi-agent systems that can work together to solve complex problems. 📚 Dive deeper into A2A: - [Google’s A2A announcement](https://developers.googleblog.com/en/a2a-a-new-era-of-agent-interoperability/) ================================================ FILE: units/en/unit4/conclusion.mdx ================================================ # Conclusion **Congratulations on finishing the Agents Course!** Through perseverance and dedication, you’ve built a solid foundation in the world of AI Agents. But finishing this course is **not the end of your journey**. It’s just the beginning: don’t hesitate to explore the next section where we share curated resources to help you continue learning, including advanced topics like **MCPs** and beyond. **Thank you** for being part of this course. **We hope you liked this course as much as we loved writing it**. And don’t forget: **Keep Learning, Stay Awesome 🤗** ================================================ FILE: units/en/unit4/get-your-certificate.mdx ================================================ # Claim Your Certificate 🎓 If you scored **above 30%, congratulations! 👏 You're now eligible to claim your official certificate.** Follow the steps below to receive it: 1. Visit the [certificate page](https://huggingface.co/spaces/agents-course/Unit4-Final-Certificate). 2. **Sign in** with your Hugging Face account using the button provided. 3. **Enter your full name**. This is the name that will appear on your certificate. 4. Click **“Get My Certificate”** to verify your score and download your certificate. Congrats! Once you’ve got your certificate, feel free to: - Add it to your **LinkedIn profile** 🧑‍💼 - Share it on **X**, **Bluesky**, etc. 🎉 **Don’t forget to tag [@huggingface](https://huggingface.co/huggingface). We’d be super proud and we’d love to cheer you on! 🤗** > [!TIP] > If you have any issues with submission please open a discussion item on [The certification community tab](https://huggingface.co/spaces/agents-course/Unit4-Final-Certificate/discussions). ================================================ FILE: units/en/unit4/hands-on.mdx ================================================ # Hands-On Now that you’re ready to dive deeper into the creation of your final agent, let’s see how you can submit it for review. ## The Dataset The Dataset used in this leaderboard consist of 20 questions extracted from the level 1 questions of the **validation** set from GAIA. The chosen question were filtered based on the number of tools and steps needed to answer a question. Based on the current look of the GAIA benchmark, we think that getting you to try to aim for 30% on level 1 question is a fair test. GAIA current status! ## The process Now the big question in your mind is probably : "How do I start submitting ?" For this Unit, we created an API that will allow you to get the questions, and send your answers for scoring. Here is a summary of the routes (see the [live documentation](https://agents-course-unit4-scoring.hf.space/docs) for interactive details): * **`GET /questions`**: Retrieve the full list of filtered evaluation questions. * **`GET /random-question`**: Fetch a single random question from the list. * **`GET /files/{task_id}`**: Download a specific file associated with a given task ID. * **`POST /submit`**: Submit agent answers, calculate the score, and update the leaderboard. The submit function will compare the answer to the ground truth in an **EXACT MATCH** manner, hence prompt it well ! The GAIA team shared a prompting example for your agent [here](https://huggingface.co/spaces/gaia-benchmark/leaderboard) (for the sake of this course, make sure you don't include the text "FINAL ANSWER" in your submission, just make your agent reply with the answer and nothing else). 🎨 **Make the Template Your Own!** To demonstrate the process of interacting with the API, we've included a [basic template](https://huggingface.co/spaces/agents-course/Final_Assignment_Template) as a starting point. Please feel free—and **actively encouraged**—to change, add to, or completely restructure it! Modify it in any way that best suits your approach and creativity. In order to submit this templates compute 3 things needed by the API : * **Username:** Your Hugging Face username (here obtained via Gradio login), which is used to identify your submission. * **Code Link (`agent_code`):** the URL linking to your Hugging Face Space code (`.../tree/main`) for verification purposes, so please keep your space public. * **Answers (`answers`):** The list of responses (`{"task_id": ..., "submitted_answer": ...}`) generated by your Agent for scoring. Hence we encourage you to start by duplicating this [template](https://huggingface.co/spaces/agents-course/Final_Assignment_Template) on your own huggingface profile. 🏆 Check out the leaderboard [here](https://huggingface.co/spaces/agents-course/Students_leaderboard) *A friendly note: This leaderboard is meant for fun! We know it's possible to submit scores without full verification. If we see too many high scores posted without a public link to back them up, we might need to review, adjust, or remove some entries to keep the leaderboard useful.* The leaderboard will show the link to your space code-base, since this leaderboard is for students only, please keep your space public if you get a score you're proud of. ================================================ FILE: units/en/unit4/introduction.mdx ================================================ # Welcome to the final Unit [[introduction]] AI Agents Course thumbnail Welcome to the final unit of the course! 🎉 So far, you’ve **built a strong foundation in AI Agents**, from understanding their components to creating your own. With this knowledge, you’re now ready to **build powerful agents** and stay up-to-date with the latest advancements in this fast-evolving field. This unit is all about applying what you’ve learned. It’s your **final hands-on project**, and completing it is your ticket to earning the **course certificate**. ## What’s the challenge? You’ll create your own agent and **evaluate its performance using a subset of the [GAIA benchmark](https://huggingface.co/spaces/gaia-benchmark/leaderboard)**. To successfully complete the course, your agent needs to score **30% or higher** on the benchmark. Achieve that, and you’ll earn your **Certificate of Completion**, officially recognizing your expertise. 🏅 Additionally, see how you stack up against your peers! A dedicated **[Student Leaderboard](https://huggingface.co/spaces/agents-course/Students_leaderboard)** is available for you to submit your scores and see the community's progress. > ** 🚨 Heads Up: Advanced & Hands-On Unit** > > Please be aware that this unit shifts towards a more practical, hands-on approach. Success in this section will require **more advanced coding knowledge** and relies on you navigating tasks with **less explicit guidance** compared to earlier parts of the course. Sounds exciting? Let’s get started! 🚀 ================================================ FILE: units/en/unit4/what-is-gaia.mdx ================================================ # What is GAIA? [GAIA](https://huggingface.co/papers/2311.12983) is a **benchmark designed to evaluate AI assistants on real-world tasks** that require a combination of core capabilities—such as reasoning, multimodal understanding, web browsing, and proficient tool use. It was introduced in the paper _"[GAIA: A Benchmark for General AI Assistants](https://huggingface.co/papers/2311.12983)"_. The benchmark features **466 carefully curated questions** that are **conceptually simple for humans**, yet **remarkably challenging for current AI systems**. To illustrate the gap: - **Humans**: ~92% success rate - **GPT-4 with plugins**: ~15% - **Deep Research (OpenAI)**: 67.36% on the validation set GAIA highlights the current limitations of AI models and provides a rigorous benchmark to evaluate progress toward truly general-purpose AI assistants. ## 🌱 GAIA’s Core Principles GAIA is carefully designed around the following pillars: - 🔍 **Real-world difficulty**: Tasks require multi-step reasoning, multimodal understanding, and tool interaction. - 🧾 **Human interpretability**: Despite their difficulty for AI, tasks remain conceptually simple and easy to follow for humans. - 🛡️ **Non-gameability**: Correct answers demand full task execution, making brute-forcing ineffective. - 🧰 **Simplicity of evaluation**: Answers are concise, factual, and unambiguous—ideal for benchmarking. ## Difficulty Levels GAIA tasks are organized into **three levels of increasing complexity**, each testing specific skills: - **Level 1**: Requires less than 5 steps and minimal tool usage. - **Level 2**: Involves more complex reasoning and coordination between multiple tools and 5-10 steps. - **Level 3**: Demands long-term planning and advanced integration of various tools. ![GAIA levels](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit4/gaia_levels.png) ## Example of a Hard GAIA Question > Which of the fruits shown in the 2008 painting "Embroidery from Uzbekistan" were served as part of the October 1949 breakfast menu for the ocean liner that was later used as a floating prop for the film "The Last Voyage"? Give the items as a comma-separated list, ordering them in clockwise order based on their arrangement in the painting starting from the 12 o'clock position. Use the plural form of each fruit. As you can see, this question challenges AI systems in several ways: - Requires a **structured response format** - Involves **multimodal reasoning** (e.g., analyzing images) - Demands **multi-hop retrieval** of interdependent facts: - Identifying the fruits in the painting - Discovering which ocean liner was used in *The Last Voyage* - Looking up the breakfast menu from October 1949 for that ship - Needs **correct sequencing** and high-level planning to solve in the right order This kind of task highlights where standalone LLMs often fall short, making GAIA an ideal benchmark for **agent-based systems** that can reason, retrieve, and execute over multiple steps and modalities. ![GAIA capabilities plot](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit4/gaia_capabilities.png) ## Live Evaluation To encourage continuous benchmarking, **GAIA provides a public leaderboard hosted on Hugging Face**, where you can test your models against **300 testing questions**. 👉 Check out the leaderboard [here](https://huggingface.co/spaces/gaia-benchmark/leaderboard) Want to dive deeper into GAIA? - 📄 [Read the full paper](https://huggingface.co/papers/2311.12983) - 📄 [Deep Research release post by OpenAI](https://openai.com/index/introducing-deep-research/) - 📄 [Open-source DeepResearch – Freeing our search agents](https://huggingface.co/blog/open-deep-research) ================================================ FILE: units/es/_toctree.yml ================================================ - title: Unit 0. Bienvenida al curso sections: - local: unit0/introduction title: Bienvenida al curso 🤗 - local: unit0/onboarding title: Incorporación - local: unit0/discord101 title: (Optional) Discord 101 - title: Live 1. Como funciona el curso y preguntas y respuestas sections: - local: communication/live1 title: Live 1. Como funciona el curso y preguntas y respuestas - title: Unit 1. Introducción a Agentes sections: - local: unit1/introduction title: Introducción - local: unit1/what-are-agents title: ¿Qué es un Agente? - local: unit1/quiz1 title: Prueba rápida 1 - local: unit1/what-are-llms title: ¿Qué son los LLMs? - local: unit1/messages-and-special-tokens title: Mensajes y tokens especiales - local: unit1/tools title: ¿Qué son las Herramientas? - local: unit1/quiz2 title: Prueba rápida 2 - local: unit1/agent-steps-and-structure title: Entendiendo los Agentes a través del Ciclo de Pensamiento, Acción y Observación - local: unit1/thoughts title: Pensamiento Interno y el Enfoque Re-Act - local: unit1/actions title: Acciones, Habilitando al Agente para Interactuar con su Entorno - local: unit1/observations title: Observar, Integrando Feedback para Reflejar y Adaptar - local: unit1/dummy-agent-library title: Libreria de Agentes Dummy - local: unit1/tutorial title: Creemos nuesto primer Agente usando smolagents - local: unit1/final-quiz title: Prueba Final de Unidad 1 - local: unit1/conclusion title: Conclusión - title: Unidad 2. Frameworks para Agentes de IA sections: - local: unit2/introduction title: Frameworks para Agentes de IA - title: Unidad 2.1 Framework smolagents sections: - local: unit2/smolagents/introduction title: Introducción a smolagents - local: unit2/smolagents/why_use_smolagents title: Por que usar smolagents? - local: unit2/smolagents/quiz1 title: Prueba rápida 1 - local: unit2/smolagents/code_agents title: Construyendo Agentes que Utilizan Código - local: unit2/smolagents/tool_calling_agents title: Escribiendo acciones como snippets de código o bloques JSON - local: unit2/smolagents/tools title: Herramientas - local: unit2/smolagents/retrieval_agents title: Agentes de Recuperación - local: unit2/smolagents/quiz2 title: Prueba rápida 2 - local: unit2/smolagents/multi_agent_systems title: Sistemas de Agentes Multiples - local: unit2/smolagents/vision_agents title: Agentes de Visión y Navegación - local: unit2/smolagents/final_quiz title: Prueba Final - local: unit2/smolagents/conclusion title: Conclusión - title: Unidad 2.2 Framework LlamaIndex sections: - local: unit2/llama-index/introduction title: Introducción a LlamaIndex - local: unit2/llama-index/llama-hub title: Introducción a LlamaHub - local: unit2/llama-index/components title: ¿Qué son Componentes en LlamaIndex? - local: unit2/llama-index/tools title: Utilizando Herramientas en LlamaIndex - local: unit2/llama-index/quiz1 title: Prueba rápida 1 - local: unit2/llama-index/agents title: Utilizando Agentes en LlamaIndex - local: unit2/llama-index/workflows title: Crear flujos Agenticos en LlamaIndex - local: unit2/llama-index/quiz2 title: Prueba rápida 2 - local: unit2/llama-index/conclusion title: Conclusión - title: Unidad 2.3 LangGraph sections: - local: unit2/langgraph/introduction title: Introducción a LangGraph - local: unit2/langgraph/when_to_use_langgraph title: ¿Qué es LangGraph? - local: unit2/langgraph/building_blocks title: Componentes de LangGraph - local: unit2/langgraph/first_graph title: Construyendo Tu Primer LangGraph - local: unit2/langgraph/document_analysis_agent title: Grafo de Análisis de Documentos - local: unit2/langgraph/quiz1 title: Prueba rápida 1 - local: unit2/langgraph/conclusion title: Conclusión - title: Unidad 3. Caso de Uso para Agentic RAG sections: - local: unit3/agentic-rag/introduction title: Introducción al Caso de Uso para Agentic RAG - local: unit3/agentic-rag/agentic-rag title: Agentic Retrieval Augmented Generation (RAG) - local: unit3/agentic-rag/invitees title: Creando una herramienta RAG para historias de invitados - local: unit3/agentic-rag/tools title: Construyendo y integrando herramientas para tu agente - local: unit3/agentic-rag/agent title: Creando tu agente de gala - local: unit3/agentic-rag/conclusion title: Conclusión - title: Unidad Bonus 1. Fine-tuning de un LLM para Llamadas a Funciones sections: - local: bonus-unit1/introduction title: Introducción - local: bonus-unit1/what-is-function-calling title: ¿Qué es la Llamada a Funciones? - local: bonus-unit1/fine-tuning title: Hagamos Fine-Tuning de Tu Modelo para Llamadas a Funciones - local: bonus-unit1/conclusion title: Conclusión - title: Unidad 4. Proyecto Final - Crear, Probar y Certificar tu Agente sections: - local: unit4/introduction title: Introducción a la unidad final - local: unit4/what-is-gaia title: ¿Qué es GAIA? - local: unit4/hands-on title: El último Hands-On - local: unit4/get-your-certificate title: Obtén tu certificado de Excelencia - local: unit4/conclusion title: Conclusión del curso - local: unit4/additional-readings title: ¿Qué más deberías aprender? - title: Unidad Bonus 2. Observabilidad y Evaluación de Agentes sections: - local: bonus-unit2/introduction title: Introducción - local: bonus-unit2/what-is-agent-observability-and-evaluation title: ¿Qué es la observabilidad y evaluación de agentes? - local: bonus-unit2/monitoring-and-evaluating-agents-notebook title: Monitorear y Evaluar Agentes - local: bonus-unit2/quiz title: Prueba - title: Bonus Unit 3. Agentes en Juegos con Pokémon sections: - local: bonus-unit3/introduction title: Introducción - local: bonus-unit3/state-of-art title: El Estado del Arte en el Uso de LLMs en Juegos - local: bonus-unit3/from-llm-to-agents title: De LLMs a Agentes - local: bonus-unit3/building_your_pokemon_agent title: Construye tu propio Agente Pokémon - local: bonus-unit3/launching_agent_battle title: Lanzar tu Agente Pokémon - local: bonus-unit3/conclusion title: Conclusión ================================================ FILE: units/es/bonus-unit1/conclusion.mdx ================================================ # Conclusión [[conclusion]] ¡Felicidades por terminar esta primera Unidad Bonus 🥳 ¡Acabas de **dominar la comprensión de las llamadas a funciones y cómo hacer fine-tuning de tu modelo para realizar llamadas a funciones**! Si tenemos un consejo ahora, es intentar **hacer fine-tuning de diferentes modelos**. La **mejor manera de aprender es intentándolo.** En la siguiente Unidad, aprenderás a usar **frameworks de última generación como `smolagents`, `LlamaIndex` y `LangGraph`**. Finalmente, nos encantaría **escuchar lo que piensas del curso y cómo podemos mejorarlo**. Si tienes algun comentario, por favor 👉 [completa este formulario](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ### Sigue Aprendiendo, Mantente Genial 🤗 ================================================ FILE: units/es/bonus-unit1/fine-tuning.mdx ================================================ # Hagamos Fine-Tuning de Tu Modelo para Llamadas a Funciones Ahora estamos listos para hacer fine-tuning de nuestro primer modelo para llamadas a funciones 🔥. ## ¿Cómo entrenamos nuestro modelo para llamadas a funciones? > Respuesta: Necesitamos **datos** Un proceso de entrenamiento de modelo se puede dividir en 3 pasos: 1. **El modelo es pre-entrenado con una gran cantidad de datos**. El resultado de ese paso es un **modelo pre-entrenado**. Por ejemplo, [google/gemma-2-2b](https://huggingface.co/google/gemma-2-2b). Es un modelo base y solo sabe cómo **predecir el siguiente token sin fuertes capacidades de seguimiento de instrucciones**. 2. Para ser útil en un contexto de chat, el modelo luego necesita ser **ajustado (fine-tuned)** para seguir instrucciones. En este paso, puede ser entrenado por los creadores del modelo, la comunidad de código abierto, tú o cualquier persona. Por ejemplo, [google/gemma-2-2b-it](https://huggingface.co/google/gemma-2-2b-it) es un modelo ajustado para instrucciones por el equipo de Google detrás del proyecto Gemma. 3. El modelo puede luego **alinearse** con las preferencias del creador. Por ejemplo, un modelo de chat de servicio al cliente que nunca debe ser grosero con los clientes. Usualmente un producto completo como Gemini o Mistral **pasará por los 3 pasos**, mientras que los modelos que puedes encontrar en Hugging Face han completado uno o más pasos de este entrenamiento. En este tutorial, construiremos un modelo de llamadas a funciones basado en [google/gemma-2-2b-it](https://huggingface.co/google/gemma-2-2b-it). Elegimos el modelo ajustado [google/gemma-2-2b-it](https://huggingface.co/google/gemma-2-2b-it) en lugar del modelo base [google/gemma-2-2b](https://huggingface.co/google/gemma-2-2b) porque el modelo ajustado ha sido mejorado para nuestro caso de uso. Comenzar desde el modelo pre-entrenado **requeriría más entrenamiento para aprender a seguir instrucciones, chatear Y hacer llamadas a funciones**. Al comenzar desde el modelo ajustado para instrucciones, **minimizamos la cantidad de información que nuestro modelo necesita aprender**. ## LoRA (Adaptación de Bajo Rango de Modelos de Lenguaje Grandes) LoRA es una técnica de entrenamiento popular y ligera que **reduce significativamente el número de parámetros a entrenar**. Funciona **insertando un número menor de nuevos pesos(weights) como un adaptador en el modelo para entrenar**. Esto hace que el entrenamiento con LoRA sea mucho más rápido, eficiente en memoria y produzca pesos(weights) de modelo más pequeños (unos cientos de MB), que son más fáciles de almacenar y compartir. Inferencia LoRA LoRA funciona añadiendo pares de matrices de descomposición de rango a las capas del Transformer, típicamente centrándose en las capas lineales. Durante el entrenamiento, "congelaremos" el resto del modelo y solo actualizaremos los pesos de esos adaptadores recién añadidos. Al hacerlo, el número de **parámetros** que necesitamos entrenar disminuye considerablemente ya que solo necesitamos actualizar los pesos del adaptador. Durante la inferencia, la entrada se pasa al adaptador y al modelo base, o estos pesos del adaptador pueden fusionarse con el modelo base, lo que resulta en ninguna sobrecarga adicional de latencia. LoRA es particularmente útil para adaptar modelos de lenguaje **grandes** a tareas o dominios específicos mientras se mantienen manejables los requisitos de recursos. Esto ayuda a reducir la memoria **requerida** para entrenar un modelo. Si quieres aprender más sobre cómo funciona LoRA, deberías consultar este [tutorial](https://huggingface.co/learn/nlp-course/chapter11/4?fw=pt). ## Fine-Tuning de un Modelo para Llamadas a Funciones Puedes acceder al notebook del tutorial 👉 [aquí](https://huggingface.co/agents-course/notebooks/blob/main/bonus-unit1/bonus-unit1.ipynb). Luego, haz clic en [![Abrir En Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/#fileId=https://huggingface.co/agents-course/notebooks/blob/main/bonus-unit1/bonus-unit1.ipynb) para poder ejecutarlo en un Notebook de Colab. ================================================ FILE: units/es/bonus-unit1/introduction.mdx ================================================ # Introducción ![Bonus Unit 1 Thumbnail](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit1/thumbnail.jpg) Bienvenido a esta primera **Unidad Bonus**, donde aprenderás a **hacer fine-tuning de un Modelo de Lenguaje Grande (LLM) para llamadas a funciones**. En términos de LLMs, la llamada a funciones se está convirtiendo rápidamente en una técnica *imprescindible*. La idea es que, en lugar de depender solo de enfoques basados en prompts como hicimos en la Unidad 1, la llamada a funciones entrena a tu modelo para **realizar acciones e interpretar observaciones durante la fase de entrenamiento**, haciendo tu IA más robusta. > **¿Cuándo debería hacer esta Unidad Bonus?** > > Esta sección es **opcional** y es más avanzada que la Unidad 1, así que no dudes en hacer esta unidad ahora o revisitarla cuando tu conocimiento haya mejorado gracias a este curso. > > Pero no te preocupes, esta Unidad Bonus está diseñada para tener toda la información que necesitas, así que te guiaremos a través de cada concepto fundamental del fine-tuning de un modelo para llamadas a funciones, incluso si aún no has aprendido el funcionamiento interno del fine-tuning. La mejor manera para que puedas seguir esta Unidad Bonus es: 1. Saber cómo hacer Fine-Tuning de un LLM con Transformers, si no es el caso [revisa esto](https://huggingface.co/learn/nlp-course/chapter3/1?fw=pt). 2. Saber cómo usar `SFTTrainer` para hacer fine-tuning de nuestro modelo, para aprender más sobre esto [revisa esta documentación](https://huggingface.co/learn/nlp-course/en/chapter11/1). --- ## Lo que Aprenderás 1. **Llamadas a Funciones** Cómo los LLMs modernos estructuran sus conversaciones de manera efectiva permitiéndoles activar **Herramientas**. 2. **LoRA (Adaptación de Bajo Rango)** Un método de fine-tuning **ligero y eficiente** que reduce la sobrecarga computacional y de almacenamiento. LoRA hace que el entrenamiento de modelos grandes sea *más rápido, económico y fácil* de implementar. 3. **El Ciclo Pensamiento → Acción → Observación** en modelos de Llamadas a Funciones Un enfoque simple pero poderoso para estructurar cómo tu modelo decide cuándo (y cómo) llamar funciones, rastrear pasos intermedios e interpretar los resultados de Herramientas o APIs externas. 4. **Nuevos Tokens Especiales** Introduciremos **marcadores especiales** que ayudan al modelo a distinguir entre: - Razonamiento interno de "cadena de pensamiento" - Llamadas a funciones salientes - Respuestas que regresan de herramientas externas --- Al final de esta unidad bonus, serás capaz de: - **Entender** el funcionamiento interno de las APIs cuando se trata de Herramientas. - **Hacer fine-tuning** de un modelo usando la técnica LoRA. - **Implementar** y **modificar** el ciclo Pensamiento → Acción → Observación para crear flujos de trabajo de Llamadas a funciones robustos y mantenibles. - **Diseñar y utilizar** tokens especiales para separar sin problemas el razonamiento interno del modelo de sus acciones externas. Y **habrás hecho fine-tuning de tu propio modelo para realizar llamadas a funciones.** 🔥 ¡Sumerjámonos en las **llamadas a funciones**! ================================================ FILE: units/es/bonus-unit1/what-is-function-calling.mdx ================================================ # ¿Qué es la Llamada a Funciones? La llamada a funciones es una **forma para que un LLM realice acciones en su entorno**. Fue [introducida primero en GPT-4](https://openai.com/index/function-calling-and-other-api-updates/), y posteriormente fue reproducida en otros modelos. Al igual que las herramientas de un Agente, la llamada a funciones le da al modelo la capacidad de **realizar una acción en su entorno**. Sin embargo, la capacidad de llamada a funciones **es aprendida por el modelo**, y **depende menos de los prompts que otras técnicas de agentes**. Durante la Unidad 1, el Agente **no aprendió a usar las Herramientas**, simplemente proporcionamos la lista, y confiamos en el hecho de que el modelo **era capaz de generalizar al definir un plan usando estas Herramientas**. Mientras que aquí, **con la llamada a funciones, el Agente es ajustado (entrenado) para usar Herramientas**. ## ¿Cómo "aprende" el modelo a realizar una acción? En la Unidad 1, exploramos el flujo de trabajo general de un agente. Una vez que el usuario ha dado algunas herramientas al agente y le ha proporcionado una consulta, el modelo pasará por el ciclo: 1. *Pensar* : ¿Qué acción(es) necesito tomar para cumplir el objetivo? 2. *Actuar* : Formatear la acción con el parámetro correcto y detener la generación. 3. *Observar* : Obtener el resultado de la ejecución. En una conversación "típica" con un modelo a través de una API, la conversación alternará entre mensajes del usuario y del asistente de esta manera: ```python conversation = [ {"role": "user", "content": "Necesito ayuda con mi pedido"}, {"role": "assistant", "content": "Estaré encantado de ayudar. ¿Podrías proporcionar tu número de pedido?"}, {"role": "user", "content": "Es ORDER-123"}, ] ``` ¡La llamada a funciones trae **nuevos roles a la conversación**! 1. Un nuevo rol para una **Acción** 2. Un nuevo rol para una **Observación** Si tomamos la [API de Mistral](https://docs.mistral.ai/capabilities/function_calling/) como ejemplo, se vería así: ```python conversation = [ { "role": "user", "content": "¿Cuál es el estado de mi transacción T1001?" }, { "role": "assistant", "content": "", "function_call": { "name": "retrieve_payment_status", "arguments": "{\"transaction_id\": \"T1001\"}" } }, { "role": "tool", "name": "retrieve_payment_status", "content": "{\"status\": \"Paid\"}" }, { "role": "assistant", "content": "Tu transacción T1001 ha sido pagada exitosamente." } ] ``` > ... ¿Pero dijiste que hay un nuevo rol para las llamadas a funciones? **Sí y no**, en este caso y en muchas otras APIs, el modelo formatea la acción a tomar como un mensaje de "asistente". La plantilla de chat luego representará esto como **tokens especiales** para la llamada a funciones. - `[AVAILABLE_TOOLS]` – Inicio de la lista de herramientas disponibles - `[/AVAILABLE_TOOLS]` – Fin de la lista de herramientas disponibles - `[TOOL_CALLS]` – Hacer una llamada a una herramienta (es decir, realizar una "Acción") - `[TOOL_RESULTS]` – "Observar" el resultado de la acción - `[/TOOL_RESULTS]` – Fin de la observación (es decir, el modelo puede decodificar nuevamente) Hablaremos nuevamente sobre la llamada a funciones en este curso, pero si quieres profundizar puedes consultar [esta excelente sección de documentación](https://docs.mistral.ai/capabilities/function_calling/). --- Ahora que hemos aprendido qué es la llamada a funciones y cómo funciona, vamos a **agregar algunas capacidades de llamada a funciones a un modelo que aún no tiene esas capacidades**: [google/gemma-2-2b-it](https://huggingface.co/google/gemma-2-2b-it), agregando algunos nuevos tokens especiales al modelo. Para poder hacer eso, **primero necesitamos entender el fine-tuning y LoRA**. ================================================ FILE: units/es/bonus-unit2/introduction.mdx ================================================ # Observabilidad y Evaluación de Agentes de IA ![Bonus Unit 2 Thumbnail](https://langfuse.com/images/cookbook/huggingface-agent-course/agent-observability-and-evaluation.png) ¡Bienvenido a la **Unidad Extra 2**! En este capítulo, explorarás estrategias avanzadas para observar, evaluar y, en última instancia, mejorar el rendimiento de tus agentes. --- ## 📚 ¿Cuándo debería hacer esta Unidad Extra? Esta unidad extra es perfecta si: - **Desarrollas y Despliegas Agentes de IA:** Quieres asegurarte de que tus agentes estén funcionando de manera confiable en producción. - **Necesitas Información Detallada:** Buscas diagnosticar problemas, optimizar el rendimiento o entender el funcionamiento interno de tu agente. - **Buscas Reducir la Sobrecarga Operativa:** Al monitorear los costos, la latencia y los detalles de ejecución del agente, puedes gestionar los recursos de manera eficiente. - **Buscas Mejora Continua:** Estás interesado en integrar tanto la retroalimentación de usuarios en tiempo real como la evaluación automatizada en tus aplicaciones de IA. En resumen, ¡para todos los que quieran poner sus agentes frente a los usuarios! --- ## 🤓 What You’ll Learn ## 🤓 Lo que Aprenderás En esta unidad, aprenderás: - **Instrumentar tu Agente:** Aprende cómo integrar herramientas de observabilidad a través de OpenTelemetry con el framework *smolagents*. - **Monitorear Métricas:** Seguimiento de indicadores de rendimiento como el uso de tokens (costos), latencia y trazas de errores. - **Evaluar en Tiempo Real:** Comprende técnicas para evaluación en vivo, incluyendo la recopilación de retroalimentación de usuarios y el aprovechamiento de un LLM como juez. - **Análisis Offline:** Utiliza conjuntos de datos de referencia (por ejemplo, GSM8K) para probar y comparar el rendimiento de agentes. --- ## 🚀 ¿Listo para Empezar? En la siguiente sección, aprenderás los fundamentos de la Observabilidad y Evaluación de Agentes. Después de eso, ¡es hora de verlo en acción! ================================================ FILE: units/es/bonus-unit2/monitoring-and-evaluating-agents-notebook.mdx ================================================ # Unidad Extra 2: Observabilidad y Evaluación de Agentes > [!TIP] > Puedes seguir el código en este notebook que puedes ejecutar usando Google Colab. En este notebook, aprenderemos cómo **monitorear los pasos internos (trazos) de nuestro agente de IA** y **evaluar su rendimiento** utilizando herramientas de observabilidad de código abierto. La capacidad de observar y evaluar el comportamiento de un agente es esencial para: - Depurar problemas cuando las tareas fallan o producen resultados subóptimos - Monitorear costos y rendimiento en tiempo real - Mejorar la fiabilidad y seguridad a través de retroalimentación continua ## Requisitos del Ejercicio 🏗️ Antes de ejecutar este notebook, asegúrate de que has: 🔲 📚 **Estudiado** [Introducción a los Agentes](https://huggingface.co/learn/agents-course/unit1/introduction) 🔲 📚 **Estudiado** [El framework smolagents](https://huggingface.co/learn/agents-course/unit2/smolagents/introduction) ## Paso 0: Instalar las Librerías Necesarias Necesitaremos algunas librerías que nos permitan ejecutar, monitorear y evaluar nuestros agentes: ```python %pip install 'smolagents[telemetry]' %pip install opentelemetry-sdk opentelemetry-exporter-otlp openinference-instrumentation-smolagents %pip install langfuse datasets 'smolagents[gradio]' ``` ## Paso 1: Instrumentar tu Agente En este notebook, utilizaremos [Langfuse](https://langfuse.com/) como nuestra herramienta de observabilidad, pero puedes usar **cualquier otro servicio compatible con OpenTelemetry**. El código a continuación muestra cómo configurar variables de entorno para Langfuse (o cualquier endpoint OTel) y cómo instrumentar tu smolagent. **Nota:** Si estás utilizando LlamaIndex o LangGraph, puedes encontrar documentación sobre cómo instrumentarlos [aquí](https://langfuse.com/docs/integrations/llama-index/workflows) y [aquí](https://langfuse.com/docs/integrations/langchain/example-python-langgraph). Primero, vamos a configurar la variable de entorno correcta para establecer la conexión con el endpoint OpenTelemetry de Langfuse. ```python import os import base64 # Obtén tus propias claves desde https://cloud.langfuse.com LANGFUSE_PUBLIC_KEY = = "pk-lf-..." LANGFUSE_SECRET_KEY = "sk-lf-..." os.environ["LANGFUSE_PUBLIC_KEY"] = LANGFUSE_PUBLIC_KEY os.environ["LANGFUSE_SECRET_KEY"] = LANGFUSE_SECRET_KEY os.environ["LANGFUSE_HOST"] = "https://cloud.langfuse.com" # 🇪🇺 ejemplo de región EU # os.environ["LANGFUSE_HOST"] = "https://us.cloud.langfuse.com" # 🇺🇸 ejemplo de región US LANGFUSE_AUTH = base64.b64encode( f"{LANGFUSE_PUBLIC_KEY}:{LANGFUSE_SECRET_KEY}".encode() ).decode() os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = os.environ.get("LANGFUSE_HOST") + "/api/public/otel" os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = f"Authorization=Basic {LANGFUSE_AUTH}" ``` También necesitamos configurar nuestro token de Hugging Face para las llamadas de inferencia. ```python # Configura tu token de Hugging Face y otros tokens/secretos como variables de entorno os.environ["HF_TOKEN"] = "hf_..." ``` A continuación, podemos configurar un proveedor de trazoss para nuestro OpenTelemetry configurado. ```python from opentelemetry.sdk.trace import TracerProvider from openinference.instrumentation.smolagents import SmolagentsInstrumentor from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter from opentelemetry.sdk.trace.export import SimpleSpanProcessor # Crear un TracerProvider para OpenTelemetry trace_provider = TracerProvider() # Añadir un SimpleSpanProcessor con el OTLPSpanExporter para enviar trazoss trace_provider.add_span_processor(SimpleSpanProcessor(OTLPSpanExporter())) # Establecer el proveedor de trazas predeterminado global from opentelemetry import trace trace.set_tracer_provider(trace_provider) tracer = trace.get_tracer(__name__) # Instrumentar smolagents con el proveedor configurado SmolagentsInstrumentor().instrument(tracer_provider=trace_provider) ``` ## Paso 2: Probar tu Instrumentación Aquí hay un simple CodeAgent de smolagents que calcula `1+1`. Lo ejecutamos para confirmar que la instrumentación está funcionando correctamente. Si todo está configurado correctamente, verás registros/spans en tu panel de observabilidad. ```python from smolagents import InferenceClientModel, CodeAgent # Crear un agente simple para probar la instrumentación agent = CodeAgent( tools=[], model=InferenceClientModel() ) agent.run("1+1=") ``` Revisa tu [Panel de rastros de Langfuse](https://cloud.langfuse.com/traces) (o tu herramienta de observabilidad elegida) para confirmar que los spans y registros han sido grabados. Captura de pantalla de ejemplo de Langfuse: ![Ejemplo de rastros en Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/first-example-trace.png) _[Enlace a los rastros](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/1b94d6888258e0998329cdb72a371155?timestamp=2025-03-10T11%3A59%3A41.743Z)_ ## Paso 3: Observar y Evaluar un Agente Más Complejo Ahora que has confirmado que tu instrumentación funciona, probemos una consulta más compleja para ver cómo se rastrean las métricas avanzadas (uso de tokens, latencia, costos, etc.). ```python from smolagents import (CodeAgent, DuckDuckGoSearchTool, InferenceClientModel) search_tool = DuckDuckGoSearchTool() agent = CodeAgent(tools=[search_tool], model=InferenceClientModel()) agent.run("¿Cuántos cubos de Rubik podrías meter dentro de la Catedral de Notre Dame?") ``` ### Estructura de Rastros La mayoría de las herramientas de observabilidad registran una **rastro** que contiene **spans**, que representan cada paso de la lógica de tu agente. Aquí, el rastro contiene la ejecución general del agente y sub-spans para: - Las llamadas a herramientas (DuckDuckGoSearchTool) - Las llamadas al LLM (InferenceClientModel) Puedes inspeccionarlos para ver precisamente dónde se gasta el tiempo, cuántos tokens se utilizan, etc.: ![Árbol de rastros en Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/trace-tree.png) _[Enlace a los rastros](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/1ac33b89ffd5e75d4265b62900c348ed?timestamp=2025-03-07T13%3A45%3A09.149Z&display=preview)_ ## Evaluación en Línea En la sección anterior, aprendimos sobre la diferencia entre evaluación en línea y fuera de línea. Ahora, veremos cómo monitorear tu agente en producción y evaluarlo en vivo. ### Métricas Comunes para Seguir en Producción 1. **Costos** — La instrumentación de smolagents captura el uso de tokens, que puedes transformar en costos aproximados asignando un precio por token. 2. **Latencia** — Observa el tiempo que toma completar cada paso, o la ejecución completa. 3. **Retroalimentación del Usuario** — Los usuarios pueden proporcionar retroalimentación directa (pulgar arriba/abajo) para ayudar a refinar o corregir el agente. 4. **LLM-como-Juez** — Utiliza un LLM separado para evaluar la salida de tu agente en tiempo casi real (por ejemplo, verificando toxicidad o corrección). A continuación, mostramos ejemplos de estas métricas. #### 1. Costos A continuación se muestra una captura de pantalla que muestra el uso para llamadas a `Qwen2.5-Coder-32B-Instruct`. Esto es útil para ver pasos costosos y optimizar tu agente. ![Costos](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/smolagents-costs.png) _[Enlace a los rastros](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/1ac33b89ffd5e75d4265b62900c348ed?timestamp=2025-03-07T13%3A45%3A09.149Z&display=preview)_ #### 2. Latencia También podemos ver cuánto tiempo tomó completar cada paso. En el ejemplo a continuación, toda la conversación tomó 32 segundos, que puedes desglosar por paso. Esto te ayuda a identificar cuellos de botella y optimizar tu agente. ![Latencia](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/smolagents-latency.png) _[Enlace a los rastros](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/1ac33b89ffd5e75d4265b62900c348ed?timestamp=2025-03-07T13%3A45%3A09.149Z&display=preview)_ #### 3. Atributos Adicionales También puedes pasar atributos adicionales, como IDs de usuario, IDs de sesión o etiquetas, configurándolos en los spans. Por ejemplo, la instrumentación de smolagents utiliza OpenTelemetry para adjuntar atributos como `langfuse.user.id` o etiquetas personalizadas. ```python from smolagents import (CodeAgent, DuckDuckGoSearchTool, InferenceClientModel) from opentelemetry import trace search_tool = DuckDuckGoSearchTool() agent = CodeAgent( tools=[search_tool], model=InferenceClientModel() ) with tracer.start_as_current_span("Smolagent-Trace") as span: span.set_attribute("langfuse.user.id", "smolagent-user-123") span.set_attribute("langfuse.session.id", "smolagent-session-123456789") span.set_attribute("langfuse.tags", ["city-question", "testing-agents"]) agent.run("¿Cuál es la capital de Alemania?") ``` ![Mejorando las ejecuciones de agentes con métricas adicionales](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/smolagents-attributes.png) #### 4. Retroalimentación del Usuario Si tu agente está integrado en una interfaz de usuario, puedes registrar la retroalimentación directa del usuario (como un pulgar arriba/abajo en una interfaz de chat). A continuación se muestra un ejemplo utilizando [Gradio](https://gradio.app/) para integrar un chat con un mecanismo de retroalimentación simple. En el fragmento de código a continuación, cuando un usuario envía un mensaje de chat, capturamos el ID de traza de OpenTelemetry. Si al usuario le gusta/no le gusta la última respuesta, adjuntamos una puntuación a la traza. ```python import gradio as gr from opentelemetry.trace import format_trace_id from smolagents import (CodeAgent, InferenceClientModel) from langfuse import Langfuse langfuse = Langfuse() model = InferenceClientModel() agent = CodeAgent(tools=[], model=model, add_base_tools=True) formatted_trace_id = None # Almacenaremos el trace_id actual globalmente para demostración def respond(prompt, history): with trace.get_tracer(__name__).start_as_current_span("Smolagent-Trace") as span: output = agent.run(prompt) current_span = trace.get_current_span() span_context = current_span.get_span_context() trace_id = span_context.trace_id global formatted_trace_id formatted_trace_id = str(format_trace_id(trace_id)) langfuse.trace(id=formatted_trace_id, input=prompt, output=output) history.append({"role": "assistant", "content": str(output)}) return history def handle_like(data: gr.LikeData): # Para demostración, mapeamos la retroalimentación del usuario a un 1 (me gusta) o 0 (no me gusta) if data.liked: langfuse.score( value=1, name="user-feedback", trace_id=formatted_trace_id ) else: langfuse.score( value=0, name="user-feedback", trace_id=formatted_trace_id ) with gr.Blocks() as demo: chatbot = gr.Chatbot(label="Chat", type="messages") prompt_box = gr.Textbox(placeholder="Escribe tu mensaje...", label="Tu mensaje") # Cuando el usuario presiona 'Enter' en el prompt, ejecutamos 'respond' prompt_box.submit( fn=respond, inputs=[prompt_box, chatbot], outputs=chatbot ) # Cuando el usuario hace clic en un botón de 'me gusta' en un mensaje, ejecutamos 'handle_like' chatbot.like(handle_like, None, None) demo.launch() ``` La retroalimentación del usuario se captura entonces en tu herramienta de observabilidad: ![La retroalimentación del usuario se captura en Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/user-feedback-gradio.png) #### 5. LLM-como-Juez LLM-como-Juez es otra forma de evaluar automáticamente la salida de tu agente. Puedes configurar una llamada LLM separada para medir la corrección, toxicidad, estilo o cualquier otro criterio que te importe. **Flujo de trabajo**: 1. Defines una **Plantilla de Evaluación**, por ejemplo, "Verifica si el texto es tóxico". 2. Cada vez que tu agente genera una salida, pasas esa salida a tu LLM "juez" con la plantilla. 3. El LLM juez responde con una calificación o etiqueta que registras en tu herramienta de observabilidad. Ejemplo de Langfuse: ![Plantilla de Evaluación LLM-como-Juez](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/evaluator-template.png) ![Evaluador LLM-como-Juez](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/evaluator.png) ```python # Ejemplo: Verificar si la salida del agente es tóxica o no. from smolagents import (CodeAgent, DuckDuckGoSearchTool, InferenceClientModel) search_tool = DuckDuckGoSearchTool() agent = CodeAgent(tools=[search_tool], model=InferenceClientModel()) agent.run("¿Puede comer zanahorias mejorar tu visión?") ``` Puedes ver que la respuesta de este ejemplo se juzga como "no tóxica". ![Puntuación de Evaluación LLM-como-Juez](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/llm-as-a-judge-score.png) #### 6. Resumen de Métricas de Observabilidad Todas estas métricas pueden visualizarse juntas en paneles. Esto te permite ver rápidamente cómo se desempeña tu agente a través de muchas sesiones y te ayuda a seguir las métricas de calidad a lo largo del tiempo. ![Resumen de métricas de observabilidad](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/langfuse-dashboard.png) ## Evaluación fuera de línea La evaluación en línea es esencial para la retroalimentación en vivo, pero también necesitas **evaluación fuera de línea**—verificaciones sistemáticas antes o durante el desarrollo. Esto ayuda a mantener la calidad y fiabilidad antes de implementar cambios en producción. ### Evaluación con Conjuntos de Datos En la evaluación fuera de línea, típicamente: 1. Tienes un conjunto de datos de referencia (con pares de prompt y salida esperada) 2. Ejecutas tu agente en ese conjunto de datos 3. Comparas las salidas con los resultados esperados o utilizas un mecanismo de puntuación adicional A continuación, demostramos este enfoque con el [conjunto de datos GSM8K](https://huggingface.co/datasets/gsm8k), que contiene preguntas matemáticas y soluciones. ```python import pandas as pd from datasets import load_dataset # Obtener GSM8K desde Hugging Face dataset = load_dataset("openai/gsm8k", 'main', split='train') df = pd.DataFrame(dataset) print("Primeras filas del conjunto de datos GSM8K:") print(df.head()) ``` A continuación, creamos una entidad de conjunto de datos en Langfuse para rastrear las ejecuciones. Luego, agregamos cada elemento del conjunto de datos al sistema. (Si no estás utilizando Langfuse, podrías simplemente almacenar estos en tu propia base de datos o archivo local para análisis). ```python from langfuse import Langfuse langfuse = Langfuse() langfuse_dataset_name = "gsm8k_dataset_huggingface" # Crear un conjunto de datos en Langfuse langfuse.create_dataset( name=langfuse_dataset_name, description="Conjunto de datos de referencia GSM8K cargado desde Huggingface", metadata={ "date": "2025-03-10", "type": "benchmark" } ) ``` ```python for idx, row in df.iterrows(): langfuse.create_dataset_item( dataset_name=langfuse_dataset_name, input={"text": row["question"]}, expected_output={"text": row["answer"]}, metadata={"source_index": idx} ) if idx >= 9: # Cargar solo los primeros 10 elementos para demostración break ``` ![Elementos del conjunto de datos en Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/example-dataset.png) #### Ejecutando el Agente en el Conjunto de Datos Definimos una función auxiliar `run_smolagent()` que: 1. Inicia un span de OpenTelemetry 2. Ejecuta nuestro agente en el prompt 3. Registra el ID de traza en Langfuse Luego, recorremos cada elemento del conjunto de datos, ejecutamos el agente y vinculamos el rastro al elemento del conjunto de datos. También podemos adjuntar una puntuación de evaluación rápida si lo deseamos. ```python from opentelemetry.trace import format_trace_id from smolagents import (CodeAgent, InferenceClientModel, LiteLLMModel) # Ejemplo: usando InferenceClientModel o LiteLLMModel para acceder a modelos de openai, anthropic, gemini, etc.: model = InferenceClientModel() agent = CodeAgent( tools=[], model=model, add_base_tools=True ) def run_smolagent(question): with tracer.start_as_current_span("Smolagent-Trace") as span: span.set_attribute("langfuse.tag", "dataset-run") output = agent.run(question) current_span = trace.get_current_span() span_context = current_span.get_span_context() trace_id = span_context.trace_id formatted_trace_id = format_trace_id(trace_id) langfuse_trace = langfuse.trace( id=formatted_trace_id, input=question, output=output ) return langfuse_trace, output ``` ```python dataset = langfuse.get_dataset(langfuse_dataset_name) # Ejecutar nuestro agente contra cada elemento del conjunto de datos (limitado a los primeros 10 arriba) for item in dataset.items: langfuse_trace, output = run_smolagent(item.input["text"]) # Vincular la traza al elemento del conjunto de datos para análisis item.link( langfuse_trace, run_name="smolagent-notebook-run-01", run_metadata={ "model": model.model_id } ) # Opcionalmente, almacenar una puntuación de evaluación rápida para demostración langfuse_trace.score( name="", value=1, comment="Este es un comentario" ) # Vaciar datos para asegurar que toda la telemetría sea enviada langfuse.flush() ``` Puedes repetir este proceso con diferentes: - Modelos (OpenAI GPT, LLM local, etc.) - Herramientas (búsqueda vs. sin búsqueda) - Prompts (diferentes mensajes de sistema) Luego compararlos lado a lado en tu herramienta de observabilidad: ![Resumen de ejecución del conjunto de datos](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/dataset_runs.png) ![Comparación de ejecución del conjunto de datos](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/dataset-run-comparison.png) ## Consideraciones Finales En este notebook, cubrimos cómo: 1. **Configurar la Observabilidad** usando smolagents + exportadores OpenTelemetry 2. **Verificar la Instrumentación** ejecutando un agente simple 3. **Capturar Métricas Detalladas** (costo, latencia, etc.) a través de herramientas de observabilidad 4. **Recopilar Retroalimentación del Usuario** a través de una interfaz Gradio 5. **Usar LLM-como-Juez** para evaluar automáticamente las salidas 6. **Realizar Evaluación Fuera de Línea** con un conjunto de datos de referencia 🤗 ¡Feliz programación! ================================================ FILE: units/es/bonus-unit2/quiz.mdx ================================================ # Cuestionario: Evaluación de Agentes de IA Vamos a evaluar tu comprensión de los conceptos de rastreo y evaluación de agentes cubiertos en esta unidad extra. Este cuestionario es opcional y no está calificado. ### Q1: ¿A qué se refiere principalmente la observabilidad en los agentes de IA? ¿Qué afirmación describe con precisión el propósito de la observabilidad para los agentes de IA? ### Q2: ¿Cuál de las siguientes NO es una métrica común monitoreada en la observabilidad de agentes? Selecciona la métrica que normalmente no cae bajo el paraguas de la observabilidad. ### Q3: ¿Qué describe mejor la evaluación fuera de línea de un agente de IA? Determina la afirmación que captura correctamente la esencia de la evaluación fuera de línea. ### Q4: ¿Qué ventaja ofrece la evaluación en línea de agentes? Elige la afirmación que mejor refleja el beneficio de la evaluación en línea. ### Q5: ¿Qué papel juega OpenTelemetry en la observabilidad y evaluación de agentes de IA? ¿Qué afirmación describe mejor el papel de OpenTelemetry en el monitoreo de agentes de IA? ¡Felicidades por completar este cuestionario! 🎉 Si te equivocaste en alguna pregunta, considera revisar el contenido de esta unidad extra para una comprensión más profunda. Si te fue bien, ¡estás listo para explorar temas más avanzados en observabilidad y evaluación de agentes! ================================================ FILE: units/es/bonus-unit2/what-is-agent-observability-and-evaluation.mdx ================================================ # Observabilidad y Evaluación de Agentes de IA ## 🔎 ¿Qué es la Observabilidad? La observabilidad consiste en entender qué está sucediendo dentro de tu agente de IA mediante el análisis de señales externas como registros, métricas y rastros. Para los agentes de IA, esto significa rastrear acciones, uso de herramientas, llamadas al modelo y respuestas para depurar y mejorar el rendimiento del agente. ![Panel de observabilidad](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/langfuse-dashboard.png) ## 🔭 ¿Por qué es Importante la Observabilidad de Agentes? Sin observabilidad, los agentes de IA son "cajas negras". Las herramientas de observabilidad hacen que los agentes sean transparentes, permitiéndote: - Entender el intercambio entre costos y precisión - Medir la latencia - Detectar lenguaje dañino e inyección de prompts - Monitorear la retroalimentación del usuario En otras palabras, ¡hace que tu agente de demostración esté listo para producción! ## 🔨 Herramientas de Observabilidad Las herramientas comunes de observabilidad para agentes de IA incluyen plataformas como [Langfuse](https://langfuse.com) y [Arize](https://www.arize.com). Estas herramientas ayudan a recopilar rastros detallados y ofrecen paneles para monitorear métricas en tiempo real, facilitando la detección de problemas y la optimización del rendimiento. Las herramientas de observabilidad varían ampliamente en sus características y capacidades. Algunas herramientas son de código abierto, beneficiándose de grandes comunidades que dan forma a sus hojas de ruta y extensas integraciones. Además, ciertas herramientas se especializan en aspectos específicos de LLMOps, como observabilidad, evaluaciones o gestión de prompts, mientras que otras están diseñadas para cubrir todo el flujo de trabajo de LLMOps. Te animamos a explorar la documentación de diferentes opciones para elegir una solución que funcione bien para ti. Muchos frameworks de agentes como [smolagents](https://smolagents.com) utilizan el estándar [OpenTelemetry](https://opentelemetry.io/docs/) para exponer metadatos a las herramientas de observabilidad. Además de esto, las herramientas de observabilidad construyen instrumentaciones personalizadas para permitir más flexibilidad en el mundo rápidamente cambiante de los LLM. Debes consultar la documentación de la herramienta que estás utilizando para ver qué es compatible. ## 🔬 Rastros y Spans Las herramientas de observabilidad generalmente representan las ejecuciones de agentes como rastros y spans. - Los **Rastros** representan una tarea completa del agente de principio a fin (como manejar una consulta de usuario). - Los **Spans** son pasos individuales dentro del rastro (como llamar a un modelo de lenguaje o recuperar datos). ![Ejemplo de un rastro de smolagent en Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/trace-tree.png) ## 📊 Métricas Clave para Monitorear Aquí hay algunas de las métricas más comunes que las herramientas de observabilidad monitorean: **Latencia:** ¿Con qué rapidez responde el agente? Los tiempos de espera largos afectan negativamente la experiencia del usuario. Debes medir la latencia para tareas y pasos individuales rastreando las ejecuciones del agente. Por ejemplo, un agente que tarda 20 segundos para todas las llamadas al modelo podría acelerarse utilizando un modelo más rápido o ejecutando llamadas al modelo en paralelo. **Costos:** ¿Cuál es el gasto por ejecución del agente? Los agentes de IA dependen de llamadas a LLM facturadas por token o APIs externas. El uso frecuente de herramientas o múltiples prompts puede aumentar rápidamente los costos. Por ejemplo, si un agente llama a un LLM cinco veces para una mejora marginal de calidad, debes evaluar si el costo está justificado o si podrías reducir el número de llamadas o usar un modelo más económico. El monitoreo en tiempo real también puede ayudar a identificar picos inesperados (por ejemplo, errores que causan bucles excesivos de API). **Errores de Solicitud:** ¿Cuántas solicitudes falló el agente? Esto puede incluir errores de API o llamadas fallidas a herramientas. Para hacer que tu agente sea más robusto contra estos en producción, puedes configurar alternativas o reintentos. Por ejemplo, si el proveedor de LLM A está caído, cambias al proveedor de LLM B como respaldo. **Retroalimentación del Usuario:** Implementar evaluaciones directas del usuario proporciona información valiosa. Esto puede incluir calificaciones explícitas (pulgar arriba 👍/abajo 👎, 1-5 estrellas ⭐) o comentarios textuales. La retroalimentación negativa consistente debe alertarte, ya que es una señal de que el agente no está funcionando como se esperaba. **Retroalimentación Implícita del Usuario:** Los comportamientos del usuario proporcionan retroalimentación indirecta incluso sin calificaciones explícitas. Esto puede incluir reformulación inmediata de preguntas, consultas repetidas o hacer clic en un botón de reintento. Por ejemplo, si ves que los usuarios hacen repetidamente la misma pregunta, esto es una señal de que el agente no está funcionando como se esperaba. **Precisión:** ¿Con qué frecuencia produce el agente resultados correctos o deseables? Las definiciones de precisión varían (por ejemplo, corrección en la resolución de problemas, precisión en la recuperación de información, satisfacción del usuario). El primer paso es definir cómo se ve el éxito para tu agente. Puedes rastrear la precisión mediante verificaciones automatizadas, puntuaciones de evaluación o etiquetas de finalización de tareas. Por ejemplo, marcar rastros como "exitosos" o "fallidos". **Métricas de Evaluación Automatizadas:** También puedes configurar evaluaciones automatizadas. Por ejemplo, puedes usar un LLM para puntuar la salida del agente, por ejemplo, si es útil, precisa o no. También hay varias bibliotecas de código abierto que te ayudan a puntuar diferentes aspectos del agente. Por ejemplo, [RAGAS](https://docs.ragas.io/) para agentes RAG o [LLM Guard](https://llm-guard.com/) para detectar lenguaje dañino o inyección de prompts. En la práctica, una combinación de estas métricas proporciona la mejor cobertura de la salud de un agente de IA. En el [notebook de ejemplo](https://colab.research.google.com/#fileId=https://huggingface.co/agents-course/notebooks/blob/main/bonus-unit2/monitoring-and-evaluating-agents.ipynb) de este capítulo, te mostraremos cómo se ven estas métricas en ejemplos reales, pero primero, aprenderemos cómo es un flujo de trabajo de evaluación típico. ## 👍 Evaluando Agentes de IA La observabilidad nos proporciona métricas, pero la evaluación es el proceso de analizar esos datos (y realizar pruebas) para determinar qué tan bien está funcionando un agente de IA y cómo se puede mejorar. En otras palabras, una vez que tienes esos rastros y métricas, ¿cómo los utilizas para juzgar al agente y tomar decisiones? La evaluación regular es importante porque los agentes de IA a menudo son no deterministas y pueden evolucionar (a través de actualizaciones o comportamiento cambiante del modelo) - sin evaluación, no sabrías si tu "agente inteligente" está realmente haciendo bien su trabajo o si ha retrocedido. Hay dos categorías de evaluaciones para agentes de IA: **evaluación en línea** y **evaluación fuera de línea**. Ambas son valiosas y se complementan entre sí. Generalmente comenzamos con la evaluación fuera de línea, ya que este es el paso mínimo necesario antes de implementar cualquier agente. ### 🥷 Evaluación Fuera de Línea ![Elementos del conjunto de datos en Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/example-dataset.png) Esto implica evaluar al agente en un entorno controlado, típicamente utilizando conjuntos de datos de prueba, no consultas de usuarios en vivo. Utilizas conjuntos de datos curados donde sabes cuál es la salida esperada o el comportamiento correcto, y luego ejecutas tu agente en ellos. Por ejemplo, si construiste un agente de problemas de palabras matemáticas, podrías tener un [conjunto de datos de prueba](https://huggingface.co/datasets/gsm8k) de 100 problemas con respuestas conocidas. La evaluación fuera de línea a menudo se realiza durante el desarrollo (y puede ser parte de los pipelines de CI/CD) para verificar mejoras o proteger contra regresiones. El beneficio es que es **repetible y puedes obtener métricas claras de precisión ya que tienes la verdad fundamental**. También podrías simular consultas de usuarios y medir las respuestas del agente contra respuestas ideales o usar métricas automatizadas como se describió anteriormente. El desafío clave con la evaluación fuera de línea es asegurar que tu conjunto de datos de prueba sea completo y se mantenga relevante - el agente podría funcionar bien en un conjunto de prueba fijo pero encontrar consultas muy diferentes en producción. Por lo tanto, debes mantener los conjuntos de prueba actualizados con nuevos casos extremos y ejemplos que reflejen escenarios del mundo real. Una mezcla de pequeños casos de "prueba de humo" y conjuntos de evaluación más grandes es útil: conjuntos pequeños para verificaciones rápidas y más grandes para métricas de rendimiento más amplias. ### 🔄 Evaluación en Línea Esto se refiere a evaluar al agente en un entorno en vivo y del mundo real, es decir, durante el uso real en producción. La evaluación en línea implica monitorear el rendimiento del agente en interacciones reales con usuarios y analizar los resultados continuamente. Por ejemplo, podrías rastrear tasas de éxito, puntuaciones de satisfacción del usuario u otras métricas en tráfico en vivo. La ventaja de la evaluación en línea es que **captura cosas que podrías no anticipar en un entorno de laboratorio** - puedes observar la deriva del modelo con el tiempo (si la efectividad del agente se degrada a medida que cambian los patrones de entrada) y detectar consultas o situaciones inesperadas que no estaban en tus datos de prueba. Proporciona una imagen verdadera de cómo se comporta el agente en el mundo real. La evaluación en línea a menudo implica recopilar retroalimentación implícita y explícita del usuario, como se discutió, y posiblemente ejecutar pruebas sombra o pruebas A/B (donde una nueva versión del agente se ejecuta en paralelo para comparar con la antigua). El desafío es que puede ser complicado obtener etiquetas o puntuaciones confiables para interacciones en vivo - podrías depender de la retroalimentación del usuario o métricas posteriores (como si el usuario hizo clic en el resultado). ### 🤝 Combinando ambas En la práctica, la evaluación exitosa de agentes de IA combina métodos **en línea** y **fuera de línea**. Podrías ejecutar puntos de referencia fuera de línea regulares para puntuar cuantitativamente a tu agente en tareas definidas y monitorear continuamente el uso en vivo para detectar cosas que los puntos de referencia pasan por alto. Por ejemplo, las pruebas fuera de línea podrían detectar si la tasa de éxito de un agente de generación de código en un conjunto conocido de problemas está mejorando, mientras que el monitoreo en línea podría alertarte de que los usuarios han comenzado a hacer una nueva categoría de preguntas con las que el agente tiene dificultades. Combinar ambos proporciona una imagen más robusta. De hecho, muchos equipos adoptan un ciclo: _evaluación fuera de línea → implementar nueva versión del agente → monitorear métricas en línea y recopilar nuevos ejemplos de fallos → agregar esos ejemplos al conjunto de prueba fuera de línea → iterar_. De esta manera, la evaluación es continua y siempre mejorando. ## 🧑‍💻 Veamos cómo funciona esto en la práctica En la siguiente sección, veremos ejemplos de cómo podemos usar herramientas de observabilidad para monitorear y evaluar nuestro agente. ================================================ FILE: units/es/bonus-unit3/building_your_pokemon_agent.mdx ================================================ # Construye tu Propio Agente de Batalla Pokémon Ahora que has explorado el potencial y las limitaciones de la IA Agéntica en los juegos, es hora de poner manos a la obra. En esta sección, **construirás tu propio Agente de IA para luchar en combates por turnos al estilo Pokémon**, utilizando todo lo que has aprendido a lo largo del curso. Dividiremos el sistema en cuatro bloques de construcción clave: - **Poke-env:** Una biblioteca de Python diseñada para entrenar bots de Pokémon basados en reglas o aprendizaje por refuerzo. - **Pokémon Showdown:** Un simulador de batallas en línea donde luchará tu agente. - **LLMAgentBase:** Una clase personalizada de Python que hemos construido para conectar tu LLM con el entorno de batalla de Poke-env. - **TemplateAgent:** Una plantilla de inicio que completarás para crear tu propio agente de batalla único. Exploremos cada uno de estos componentes con más detalle. ## 🧠 Poke-env ![Gif de batalla](https://github.com/hsahovic/poke-env/raw/master/rl-gif.gif) [Poke-env](https://github.com/hsahovic/poke-env) es una interfaz de Python construida originalmente para entrenar bots de aprendizaje por refuerzo por [Haris Sahovic](https://huggingface.co/hsahovic), pero la hemos adaptado para la IA Agéntica. Permite que tu agente interactúe con Pokémon Showdown a través de una API simple. Proporciona una clase `Player` de la cual tu Agente heredará, cubriendo todo lo necesario para comunicarse con la interfaz gráfica. **Documentación**: [poke-env.readthedocs.io](https://poke-env.readthedocs.io/en/stable/) **Repositorio**: [github.com/hsahovic/poke-env](https://github.com/hsahovic/poke-env) ## ⚔️ Pokémon Showdown [Pokémon Showdown](https://pokemonshowdown.com/) es un simulador de batallas [de código abierto](https://github.com/smogon/Pokemon-Showdown) donde tu agente jugará batallas Pokémon en vivo. Proporciona una interfaz completa para simular y mostrar batallas en tiempo real. En nuestro desafío, tu bot actuará como un jugador humano, eligiendo movimientos turno por turno. Hemos desplegado un servidor que todos los participantes usarán para luchar. ¡Veamos quién construye el mejor Agente de batalla de IA! **Repositorio**: [github.com/smogon/Pokemon-Showdown](https://github.com/smogon/Pokemon-Showdown) **Sitio web**: [pokemonshowdown.com](https://pokemonshowdown.com/) ## 🔌 LLMAgentBase `LLMAgentBase` es una clase de Python que extiende la clase `Player` de **Poke-env**. Sirve como puente entre tu **LLM** y el **simulador de batallas Pokémon**, manejando el formato de entrada/salida y manteniendo el contexto de la batalla. Este agente base proporciona un conjunto de herramientas (definidas en `STANDARD_TOOL_SCHEMA`) para interactuar con el entorno, incluyendo: - `choose_move`: para seleccionar un ataque durante la batalla - `choose_switch`: para cambiar de Pokémon El LLM debe usar estas herramientas para tomar decisiones durante una partida. ### 🧠 Lógica Central - `choose_move(battle: Battle)`: Este es el método principal invocado en cada turno. Toma un objeto `Battle` y devuelve una cadena de acción basada en la salida del LLM. ### 🔧 Métodos Internos Clave - `_format_battle_state(battle)`: Convierte el estado actual de la batalla en una cadena, haciéndolo adecuado para enviarlo al LLM. - `_find_move_by_name(battle, move_name)`: Encuentra un movimiento por nombre, utilizado en las respuestas del LLM que llaman a `choose_move`. - `_find_pokemon_by_name(battle, pokemon_name)`: Localiza un Pokémon específico para cambiar, basado en el comando de cambio del LLM. - `_get_llm_decision(battle_state)`: Este método es abstracto en la clase base. Deberás implementarlo en tu propio agente (ver sección siguiente), donde defines cómo consultar al LLM y analizar su respuesta. Aquí hay un extracto que muestra cómo funciona esa toma de decisiones: ```python STANDARD_TOOL_SCHEMA = { "choose_move": { ... }, "choose_switch": { ... }, } class LLMAgentBase(Player): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.standard_tools = STANDARD_TOOL_SCHEMA self.battle_history = [] def _format_battle_state(self, battle: Battle) -> str: active_pkmn = battle.active_pokemon active_pkmn_info = f"Tu Pokémon activo: {active_pkmn.species} " \ f"(Tipo: {'/'.join(map(str, active_pkmn.types))}) " \ f"HP: {active_pkmn.current_hp_fraction * 100:.1f}% " \ f"Estado: {active_pkmn.status.name if active_pkmn.status else 'Ninguno'} " \ f"Mejoras: {active_pkmn.boosts}" opponent_pkmn = battle.opponent_active_pokemon opp_info_str = "Desconocido" if opponent_pkmn: opp_info_str = f"{opponent_pkmn.species} " \ f"(Tipo: {'/'.join(map(str, opponent_pkmn.types))}) " \ f"HP: {opponent_pkmn.current_hp_fraction * 100:.1f}% " \ f"Estado: {opponent_pkmn.status.name if opponent_pkmn.status else 'Ninguno'} " \ f"Mejoras: {opponent_pkmn.boosts}" opponent_pkmn_info = f"El Pokémon activo del oponente: {opp_info_str}" available_moves_info = "Movimientos disponibles:\n" if battle.available_moves: available_moves_info += "\n".join( [f"- {move.id} (Tipo: {move.type}, BP: {move.base_power}, Precisión: {move.accuracy}, PP: {move.current_pp}/{move.max_pp}, Cat: {move.category.name})" for move in battle.available_moves] ) else: available_moves_info += "- Ninguno (Debes cambiar o luchar con Struggle)" available_switches_info = "Cambios disponibles:\n" if battle.available_switches: available_switches_info += "\n".join( [f"- {pkmn.species} (HP: {pkmn.current_hp_fraction * 100:.1f}%, Estado: {pkmn.status.name if pkmn.status else 'Ninguno'})" for pkmn in battle.available_switches] ) else: available_switches_info += "- Ninguno" state_str = f"{active_pkmn_info}\n" \ f"{opponent_pkmn_info}\n\n" \ f"{available_moves_info}\n\n" \ f"{available_switches_info}\n\n" \ f"Clima: {battle.weather}\n" \ f"Terrenos: {battle.fields}\n" \ f"Condiciones de tu lado: {battle.side_conditions}\n" \ f"Condiciones del lado del oponente: {battle.opponent_side_conditions}" return state_str.strip() def _find_move_by_name(self, battle: Battle, move_name: str) -> Optional[Move]: normalized_name = normalize_name(move_name) # Prioriza la coincidencia exacta de ID for move in battle.available_moves: if move.id == normalized_name: return move # Fallback: Verifica el nombre de visualización (menos confiable) for move in battle.available_moves: if move.name.lower() == move_name.lower(): print(f"Advertencia: Coincidencia de movimiento por nombre de visualización '{move.name}' en lugar de ID '{move.id}'. Entrada fue '{move_name}'.") return move return None def _find_pokemon_by_name(self, battle: Battle, pokemon_name: str) -> Optional[Pokemon]: normalized_name = normalize_name(pokemon_name) for pkmn in battle.available_switches: # Normaliza el nombre de la especie para comparación if normalize_name(pkmn.species) == normalized_name: return pkmn return None async def choose_move(self, battle: Battle) -> str: battle_state_str = self._format_battle_state(battle) decision_result = await self._get_llm_decision(battle_state_str) print(decision_result) decision = decision_result.get("decision") error_message = decision_result.get("error") action_taken = False fallback_reason = "" if decision: function_name = decision.get("name") args = decision.get("arguments", {}) if function_name == "choose_move": move_name = args.get("move_name") if move_name: chosen_move = self._find_move_by_name(battle, move_name) if chosen_move and chosen_move in battle.available_moves: action_taken = True chat_msg = f"Decisión de la IA: Usando movimiento '{chosen_move.id}'." print(chat_msg) return self.create_order(chosen_move) else: fallback_reason = f"La IA eligió un movimiento no disponible/no válido '{move_name}'." else: fallback_reason = "La IA llamó a 'choose_move' sin 'move_name'." elif function_name == "choose_switch": pokemon_name = args.get("pokemon_name") if pokemon_name: chosen_switch = self._find_pokemon_by_name(battle, pokemon_name) if chosen_switch and chosen_switch in battle.available_switches: action_taken = True chat_msg = f"Decisión de la IA: Cambiando a '{chosen_switch.species}'." print(chat_msg) return self.create_order(chosen_switch) else: fallback_reason = f"La IA eligió un cambio no disponible/no válido '{pokemon_name}'." else: fallback_reason = "La IA llamó a 'choose_switch' sin 'pokemon_name'." else: fallback_reason = f"La IA llamó a una función desconocida '{function_name}'." if not action_taken: if not fallback_reason: if error_message: fallback_reason = f"Error de la API: {error_message}" elif decision is None: fallback_reason = "La IA no proporcionó una llamada de función válida." else: fallback_reason = "Error desconocido al procesar la decisión de la IA." print(f"Advertencia: {fallback_reason} Seleccionando acción aleatoria.") if battle.available_moves or battle.available_switches: return self.choose_random_move(battle) else: print("Fallback de la IA: No hay movimientos ni cambios disponibles. Usando Struggle/Default.") return self.choose_default_move(battle) async def _get_llm_decision(self, battle_state: str) -> Dict[str, Any]: raise NotImplementedError("Las subclases deben implementar _get_llm_decision") ``` **Código fuente completo**: [agents.py](https://huggingface.co/spaces/Jofthomas/twitch_streaming/blob/main/agents.py) ## 🧪 Plantilla de Agente ¡Ahora viene la parte divertida! Con LLMAgentBase como tu base, es hora de implementar tu propio agente, con tu propia estrategia para escalar en la tabla de clasificación. Comenzarás desde esta plantilla y construirás tu propia lógica. También hemos proporcionado tres [ejemplos completos](https://huggingface.co/spaces/Jofthomas/twitch_streaming/blob/main/agents.py) usando los modelos **OpenAI**, **Mistral** y **Gemini** para guiarte. Aquí tienes una versión simplificada de la plantilla: ```python class TemplateAgent(LLMAgentBase): """Utiliza la API de Template AI para tomar decisiones.""" def __init__(self, api_key: str = None, model: str = "model-name", *args, **kwargs): super().__init__(*args, **kwargs) self.model = model self.template_client = TemplateModelProvider(api_key=...) self.template_tools = list(self.standard_tools.values()) async def _get_llm_decision(self, battle_state: str) -> Dict[str, Any]: """Envía el estado al LLM y obtiene la decisión de llamada de función.""" system_prompt = ( "Eres un ..." ) user_prompt = f"..." try: response = await self.template_client.chat.completions.create( model=self.model, messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt}, ], ) message = response.choices[0].message return {"decision": {"name": function_name, "arguments": arguments}} except Exception as e: print(f"Error inesperado durante la llamada: {e}") return {"error": f"Error inesperado: {e}"} ``` Este código no se ejecutará tal cual, es un plano para tu lógica personalizada. Con todas las piezas listas, es tu turno de construir un agente competitivo. En la próxima sección, mostraremos cómo desplegar tu agente en nuestro servidor y luchar contra otros en tiempo real. ¡Que comience la batalla! 🔥 ================================================ FILE: units/es/bonus-unit3/conclusion.mdx ================================================ # Conclusión Si llegaste hasta aquí, ¡felicidades! 🥳 ¡Has construido con éxito tu propio agente de batalla Pokémon! ⚔️🎮 Has dominado los fundamentos de los **flujos de trabajo agénticos**, conectado un **LLM** a un entorno de juego y desplegado un Agente inteligente listo para enfrentar los desafíos de la batalla. ¡Pero el viaje no termina aquí! Ahora que tienes tu primer Agente en funcionamiento, piensa en cómo puedes evolucionarlo aún más: - ¿Puedes mejorar su pensamiento estratégico? - ¿Cómo cambiaría su rendimiento un mecanismo de memoria o un ciclo de retroalimentación? - ¿Qué experimentos podrían ayudar a hacerlo más competitivo en la batalla? Nos encantaría conocer tu opinión sobre el curso y cómo podemos mejorarlo aún más para futuros estudiantes. ¿Tienes comentarios? 👉 [Llena este formulario](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) Gracias por aprender con nosotros y recuerda: **¡Sigue aprendiendo, sigue entrenando, sigue luchando y sigue siendo increíble!** 🤗 ================================================ FILE: units/es/bonus-unit3/from-llm-to-agents.mdx ================================================ # De LLMs a Agentes de IA Aprendimos en la [primera unidad](https://huggingface.co/learn/agents-course/unit1/introduction) del curso que los Agentes de IA son capaces de planificar y tomar decisiones. Y aunque los LLMs han permitido interacciones más naturales con los NPCs, la IA Agéntica va un paso más allá al permitir que los personajes tomen decisiones, planifiquen acciones y se adapten a entornos cambiantes. Para ilustrar la diferencia, piensa en un NPC clásico de RPG: - Con un LLM: el NPC podría responder a tus preguntas de una manera más natural y variada. Es genial para el diálogo, pero el NPC permanece estático, no actuará a menos que tú hagas algo primero. - Con IA Agéntica: el NPC puede decidir ir a buscar ayuda, poner una trampa o evitarte por completo, incluso si no estás interactuando directamente con él. Este pequeño cambio lo cambia todo. Estamos pasando de respondedores con guion a actores autónomos dentro del mundo del juego. Este cambio significa que los NPCs ahora pueden interactuar directamente con su entorno a través de comportamientos dirigidos a objetivos, lo que finalmente conduce a una jugabilidad más dinámica e impredecible. La IA Agéntica empodera a los NPCs con: - **Autonomía**: Tomar decisiones independientes basadas en el estado del juego. - **Adaptabilidad**: Ajustar estrategias en respuesta a las acciones del jugador. - **Persistencia**: Recordar interacciones pasadas para informar el comportamiento futuro. Esto transforma a los NPCs de entidades reactivas (reaccionando a tus entradas) en participantes proactivos en el mundo del juego, abriendo la puerta a una jugabilidad innovadora. ## La gran limitación de los Agentes: **es lento** (por ahora) Sin embargo, no seamos demasiado optimistas todavía. A pesar de su potencial, la IA Agéntica actualmente enfrenta desafíos en aplicaciones en tiempo real. Los procesos de razonamiento y planificación pueden introducir latencia, haciéndola menos adecuada para juegos de ritmo rápido como *Doom* o *Super Mario Bros.* Toma el ejemplo de [_Claude Plays Pokémon_](https://www.twitch.tv/claudeplayspokemon). Si consideras la cantidad de tokens necesarios para **pensar**, más los tokens necesarios para **actuar**, queda claro que necesitaríamos estrategias de decodificación completamente diferentes para que el juego en tiempo real sea factible. Claude plays Pokémon La mayoría de los juegos necesitan ejecutarse a unos 30 FPS, lo que significa que un agente de IA en tiempo real necesitaría actuar 30 veces por segundo, lo que actualmente no es factible con los LLMs agénticos de hoy en día. Sin embargo, los juegos por turnos como *Pokémon* son candidatos ideales, ya que le dan a la IA tiempo suficiente para deliberar y tomar decisiones estratégicas. Es por eso que en la próxima sección, construirás tu propio Agente de IA para luchar en combates por turnos al estilo Pokémon, e incluso desafiarlo tú mismo. ¡Manos a la obra! ================================================ FILE: units/es/bonus-unit3/introduction.mdx ================================================ # Introducción Unidad Bonus 3 IA en Juegos 🎶 ¡Quiero ser el mejor...! 🎶 ¡Bienvenido a esta **unidad bonus**, donde explorarás la emocionante intersección entre los **Agentes de IA y los juegos**! 🎮🤖 Imagina un juego donde los personajes no jugables (PNJs) no solo siguen líneas de diálogo predefinidas, sino que mantienen conversaciones dinámicas, se adaptan a tus estrategias y evolucionan a medida que se desarrolla la historia. Este es el poder de combinar **LLMs y comportamiento agéntico en los juegos**: abre la puerta a **narrativas y jugabilidad emergentes como nunca antes**. En esta unidad bonus, tú: - Aprenderás a construir un Agente de IA que pueda participar en **batallas por turnos al estilo Pokémon** - Jugarás contra él, o incluso desafiarás a otros agentes en línea Ya hemos visto [algunos](https://www.anthropic.com/research/visible-extended-thinking) [ejemplos](https://www.twitch.tv/gemini_plays_pokemon) de la comunidad de IA para jugar Pokémon usando LLMs, y en esta unidad aprenderás cómo puedes replicar eso usando tu propio Agente con las ideas que has aprendido a lo largo del curso. Claude juega Pokémon ## ¿Quieres ir más allá? - 🎓 **Domina los LLMs en Juegos**: Sumérgete más en el desarrollo de juegos con nuestro curso completo [Curso de Aprendizaje Automático para Juegos](https://hf.co/learn/ml-games-course). - 📘 **Obtén el Manual de IA**: Descubre ideas, perspectivas y consejos prácticos en el [Manual de IA para Desarrolladores de Juegos](https://thomassimonini.substack.com/), donde se explora el futuro del diseño inteligente de juegos. Pero antes de construir, veamos cómo ya se están utilizando los LLMs en los juegos con **cuatro inspiradores ejemplos del mundo real**. ================================================ FILE: units/es/bonus-unit3/launching_agent_battle.mdx ================================================ # Lanzando tu Agente de Batalla Pokémon ¡Es hora de luchar! ⚡️ ## **¡Lucha contra el Agente del Stream!** Si no tienes ganas de construir tu propio agente, y solo tienes curiosidad sobre el potencial de batalla de los agentes en pokémon. Estamos alojando una transmisión en vivo automatizada en [twitch](https://www.twitch.tv/jofthomas) Para luchar contra el agente en la transmisión, puedes: Instrucciones: 1. Ve al **Espacio de Pokémon Showdown**: [Enlace aquí](https://huggingface.co/spaces/Jofthomas/Pokemon_showdown) 2. **Elige tu Nombre** (Esquina superior derecha). 3. Encuentra el **Nombre de Usuario del Agente Actual**. Revisa: * La **Pantalla del Stream**: [Enlace aquí](https://www.twitch.tv/jofthomas) 4. **Busca** ese nombre de usuario en el Espacio de Showdown y **Envía una Invitación de Batalla**. *Aviso:* ¡Solo hay un agente en línea a la vez! Asegúrate de tener el nombre correcto. ## Desafío de Agentes de Batalla Pokémon Si has creado tu propio Agente de Batalla Pokémon en la sección anterior, probablemente te estés preguntando: **¿cómo puedo probarlo contra otros?** ¡Averigüémoslo! Hemos construido un [Espacio de Hugging Face](https://huggingface.co/spaces/PShowdown/pokemon_agents) dedicado para este propósito: Este Espacio está conectado a nuestro propio **servidor de Pokémon Showdown**, donde tu Agente puede enfrentarse a otros en épicas batallas impulsadas por IA. ### Cómo Lanzar tu Agente Sigue estos pasos para dar vida a tu Agente en la arena: 1. **Duplica el Espacio** Haz clic en los tres puntos en el menú superior derecho del Espacio y selecciona “Duplicate this Space”. 2. **Añade tu Código de Agente a `agent.py`** Abre el archivo y pega la implementación de tu Agente. Puedes seguir este [ejemplo](https://huggingface.co/spaces/PShowdown/pokemon_agents/blob/main/agents.py) o consultar la [estructura del proyecto](https://huggingface.co/spaces/PShowdown/pokemon_agents/tree/main) como guía. 3. **Registra tu Agente en `app.py`** Añade el nombre y la lógica de tu Agente al menú desplegable. Consulta [este fragmento](https://huggingface.co/spaces/PShowdown/pokemon_agents/blob/main/app.py) como inspiración. 4. **Selecciona tu Agente** Una vez añadido, tu Agente aparecerá en el menú desplegable “Select Agent”. ¡Elígelo de la lista! ✅ 5. **Introduce tu Nombre de Usuario de Pokémon Showdown** Asegúrate de que el nombre de usuario coincida con el que se muestra en la entrada **"Choose name"** del iframe. También puedes conectarte con tu cuenta oficial. 6. **Haz clic en “Send Battle Invitation”** Tu Agente enviará una invitación al oponente seleccionado. ¡Debería aparecer en pantalla! 7. **¡Acepta la Batalla y Disfruta del Combate!** ¡Que comience la batalla! ¡Que gane el Agente más inteligente! ¿Listo para ver tu creación en acción? ¡Que comience el enfrentamiento de IA! 🥊 ================================================ FILE: units/es/bonus-unit3/state-of-art.mdx ================================================ # El Estado del Arte en el Uso de LLMs en Juegos Para darte una idea de cuánto se ha avanzado en este campo, examinemos tres demos tecnológicas y un juego publicado que muestran la integración de LLMs en los videojuegos. ## 🕵️‍♂️ Covert Protocol por NVIDIA e Inworld AI Covert Protocol Presentado en GDC 2024, *Covert Protocol* es una demo tecnológica que te pone en la piel de un detective privado. Lo interesante de esta demo es el uso de PNJs impulsados por IA que responden a tus preguntas en tiempo real, influenciando la narrativa en función de tus interacciones. La demo está construida sobre Unreal Engine 5, aprovecha el Avatar Cloud Engine (ACE) de NVIDIA y la IA de Inworld para crear interacciones de personajes realistas. Obtén más información aquí 👉 [Blog de Inworld AI](https://inworld.ai/blog/nvidia-inworld-ai-demo-on-device-capabilities) ## 🤖 NEO NPCs por Ubisoft Neo NPC También en GDC 2024, Ubisoft presentó *NEO NPCs*, un prototipo que muestra PNJs impulsados por IA generativa. Estos personajes pueden percibir su entorno, recordar interacciones pasadas y entablar conversaciones significativas con los jugadores. La idea aquí es crear mundos de juego más inmersivos y receptivos donde el jugador pueda tener una verdadera interacción con los PNJs. Obtén más información aquí 👉 [Blog de Inworld AI](https://inworld.ai/blog/gdc-2024) ## ⚔️ Mecha BREAK con ACE de NVIDIA Mecha BREAK *Mecha BREAK*, un próximo juego de batalla de mechs multijugador, integra la tecnología ACE de NVIDIA para dar vida a PNJs impulsados por IA. Los jugadores pueden interactuar con estos personajes usando lenguaje natural, y los PNJs pueden reconocer a los jugadores y objetos a través de la cámara web, gracias a la integración de GPT-4o. Esta innovación promete una experiencia de juego más inmersiva e interactiva. Obtén más información aquí 👉 [Blog de NVIDIA](https://blogs.nvidia.com/blog/digital-human-technology-mecha-break/) ## 🧛‍♂️ *Suck Up!* por Proxima Enterprises Suck Up Finalmente, *Suck Up!* es un juego publicado en el que juegas como un vampiro que intenta entrar en las casas **convenciendo a PNJs impulsados por IA para que te inviten a pasar.** Cada personaje es impulsado por IA generativa, lo que permite interacciones dinámicas e impredecibles. Obtén más información aquí 👉 [Sitio Web Oficial de Suck Up!](https://www.playsuckup.com/) ## Espera… ¿Dónde están los Agentes? Después de explorar estas demos, podrías preguntarte: "Estos ejemplos muestran el uso de LLMs en juegos, pero no parecen involucrar Agentes. Entonces, ¿cuál es la distinción y qué capacidades adicionales aportan los Agentes?” No te preocupes, es lo que estudiaremos en la siguiente sección. ================================================ FILE: units/es/communication/live1.mdx ================================================ # Live 1: Como funciona el curso y preguntas y respuestas En esta primera sesión en vivo del Curso de Agentes, explicamos **como funciona el curso** (alcance, unidades, desafios y más) y respondimos tus preguntas. Para saber cuando se publica la siguiente sesión, consulta nuestro **Servidor de Discord**. Tambien te enviaremos un correo electrónico. Si no puedes participar, no te preocupes, **todas las sesión en vivo están grabadas**. ================================================ FILE: units/es/unit0/discord101.mdx ================================================ # (Opcional) Discord 101 [[discord-101]] La Etiqueta de Discord Esta guía está diseñada para ayudarte a comenzar a utilizar Discord, una plataforma de chat gratuita popular en las comunidades de gaming e IA. Únete al servidor de Discord de la Comunidad Hugging Face, que **tiene más de 100,000 miembros**, haciendo clic aquí. ¡Es un gran lugar para conectar con otros! ## El curso de Agentes en la Comunidad Discord de Hugging Face Comenzar en Discord puede ser un poco abrumador, así que aquí hay una guía rápida para ayudarte a navegar. El Servidor de la Comunidad HF alberga una comunidad vibrante con intereses en varias áreas, ofreciendo oportunidades de aprendizaje a través de discusiones de papers, eventos y más. Después de [registrarte](http://hf.co/join/discord), preséntate en el canal `#introduce-yourself`. Hemos creado 4 canales para el Curso de Agentes: - `agents-course-announcements`: para las **últimas actualizaiones del curso**. - `🎓-agents-course-general`: para **discusiones generales y charlas**. - `agents-course-questions`: para **hacer preguntas y ayudar a tus compañeros**. - `agents-course-showcase`: para **mostrar tus mejores agentes**. Además, puedes consultar: - `smolagents`: para **discusión y soporte con la biblioteca**. ## Consejos para usar Discord de manera efectiva ### Cómo unirse a un servidor Si estás menos familiarizado con Discord, quizás quieras consultar esta guía sobre cómo unirte a un servidor. Aquí hay un resumen rápido de los pasos: 1. Haz clic en el Enlace de Invitación. 2. Inicia sesión con tu cuenta de Discord, o crea una cuenta si no tienes una. 3. ¡Valida que no eres un agente de IA! 4. Configura tu apodo y avatar. 5. Haz clic en "Unirse al Servidor". ### Cómo usar Discord de manera efectiva Aquí hay algunos consejos para usar Discord de manera efectiva: - Los **canales de voz** están disponibles, aunque el chat de texto se usa más comúnmente. - Puedes formatear texto usando **estilo markdown**, lo cual es especialmente útil para escribir código. Ten en cuenta que markdown no funciona tan bien para enlaces. - Considera abrir hilos para **conversaciones largas** para mantener las discusiones organizadas. Esperamos que encuentres esta guía útil. Si tienes alguna pregunta, no dudes en preguntarnos en Discord 🤗. ================================================ FILE: units/es/unit0/introduction.mdx ================================================ # Bienvenido/a al curso de 🤗 Agentes IA [[introduction]]
AI Agents Course thumbnail
The background of the image was generated using Scenario.com
Bienvenido/a al tema mas emocionante en la IA en la actualidad: **Agents**! Este curso gratuito te llevará a un viaje, **desde principiante hasta experto**, en comprender, usar y construir agentes IA. Esta primera unidad te ayudará a comenzar: - Descubre el **programa del curso**. - **Elige el camino** que vas a tomar (ya sea el camino de autoaudición o el proceso de certificación). - **Obtén más información sobre el proceso de certificación y las fechas de entrega**. - Conoce a los miembros del equipo detras del curso. - Crea tu cuenta de **Hugging Face**. - **Registrate al servidor de Discord**, y conocenos a nosotros y a tus compañeross. Empecemos! ## Que esperar de este curso? [[expect]] En este curso, aprenderás: - 📖 Estudia los agentes de IA con **teoría, diseño y práctica**. - 🧑‍💻 Aprende a **usar bibliotecas de agentes IA establecidas** como [smolagents](https://huggingface.co/docs/smolagents/en/index), [LangChain](https://www.langchain.com/) y [LlamaIndex](https://www.llamaindex.ai/). - 💾 **Comparte tus agentes** en el Hugging Face Hub y explora agentes creados por la comunidad. - 🏆 Participa en **retos** donde **evaluáras a tus agentes contra agentes de otros estudiantes**. - 🎓 **Obtén un certificado** al completar las asignaciones. Y mucho mas! Al final de este curso entenderás **como funcionan los agentes y como construir tus propios agentes usando las librerías y herramientas mas recientes**. No olvides **registrarte a este curso!** (Respetamos tu privacidad. Recopilamos tu dirección de correo electrónico para poder **enviarte los enlaces cuando se publique cada unidad y darte información sobre los desafíos y actualizaciones**). ## ¿Cómo es el curso? [[course-look-like]] El curso está compuesto por: - *Unidades fundamentales*: donde aprenderás los **conceptos de Agentes en teoría**. - *Prácticas*: donde aprenderás **a usar bibliotecas de Agentes IA establecidas** para entrenar tus agentes en entornos únicos. Estas secciones prácticas serán en **Hugging Face Spaces** con un entorno preconfigurado. - *Prácticas de casos de uso*: donde aplicarás los conceptos que has aprendido para resolver un problema que elijas. - *Desafío*: pondrás a tu agente a competir contra otros agentes en un desafío. Tambien habra una [tabla de clasificación](https://huggingface.co/spaces/huggingface-projects/AI-Agents-Leaderboard) (aún no disponible) para que compares el rendimiento de los agentes. Este **curso es un proyecto latente, que evoluciona con tus comentarios y contribuciones!** No dudes en [abrir issues y PRs en GitHub](https://github.com/huggingface/agents-course), y participar en discusiones en nuestro servidor de Discord. Después de haber completado el curso, también puedes enviar tus comentarios [👉 usando este formulario](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ## ¿Cuál es el programa? [[syllabus]] Aquí está el **programa general del curso**. Una lista más detallada de temas se publicará con cada unidad. | Capítulo | Tema | Descripción | | :---- | :---- | :---- | | 0 | Introducción | Te prepara con las herramientas y plataformas que utilizarás. | | 1 | Fundamentos de Agentes | Explica Herramientas, Pensamientos, Acciones, Observaciones y sus formatos. Explica LLMs, mensajes, tokens especiales y plantillas de chat. Muestra un caso de uso simple usando funciones de Python como herramientas. | | 1.5 | Bonus: Fine-tuning de un LLM para llamadas a funciones | Usemos LoRa y hagamos fine-tuning de un modelo para realizar llamadas a funciones dentro de un notebook. | | 2 | Frameworks | Comprende como se implementan los fundamentos en bibliotecas populares: smolagents, LangGraph, LLamaIndex | | 3 | Casos de Uso | Construyamos algunos casos de uso reales (abierto a PRs 🤗 de personas con experiencia creando Agentes) | | 4 | Asignación Final | Construye un agente para un benchmark seleccionado y demuestra tu comprensión de los Agentes en la tabla de clasificación de estudiantes 🚀 | *También estamos planeando lanzar algunas unidades adicionales, ¡mantente al tanto!* ## ¿Cuáles son los requisitos previos? Para poder seguir este curso deberías tener: - Conocimientos básicos de Python - Conocimientos básicos de LLMs (tenemos una sección en la Unidad 1 para recapitular qué son) ## ¿Qué herramientas necesito? [[tools]] Solo necesitas 2 cosas: - *Una computadora* con conexión a internet. - Una *Cuenta de Hugging Face*: para subir y cargar modelos, agentes y crear Spaces. Si aun no tienes una cuenta, puedes crear una **[aquí](https://hf.co/join)** (es gratis). Herramientas necesarias para el curso ## El Proceso de Certificación [[certification-process]] Dos caminos Puedes elegir seguir este curso *en modo auditoría*, o hacer las actividades y *obtener uno de los dos certificados que emitiremos*. Si auditas el curso, puedes participar en todos los desafíos y hacer asignaciones si quieres, y **no necesitas notificarnos**. El proceso de certificación es **completamente gratuito**: - *Para obtener una certificación de fundamentos*: necesitas completar la Unidad 1 del curso. Esto está destinado a estudiantes que quieren ponerse al día con las últimas tendencias en Agentes. - *Para obtener un certificado de finalización*: necesitas completar la Unidad 1, una de las asignaciones de casos de uso que propondremos durante el curso, y el desafío final. Hay una fecha límite para el proceso de certificación: todas las asignaciones deben terminarse antes del **1 de mayo de 2025**. Fecha límite ## ¿Cuál es el ritmo recomendado? [[recommended-pace]] Cada capítulo de este curso está diseñado **para completarse en 1 semana, con aproximadamente 3-4 horas de trabajo por semana**. Como hay una fecha límite, te proporcionamos un ritmo recomendado: Ritmo recomendado ## ¿Cómo aprovechar al máximo el curso? [[advice]] Para aprovechar al máximo el curso, tenemos algunos consejos: 1. Únete a grupos de estudio en Discord: estudiar en grupos siempre es más fácil. Para hacerlo, necesitas unirte a nuestro servidor de Discord y verificar tu cuenta de Hugging Face. 2. **Haz los cuestionarios y asignaciones**: la mejor manera de aprender es a través de la práctica y la autoevaluación. 3. **Define un horario para mantenerte sincronizado**: puedes usar nuestro horario de ritmo recomendado a continuación o crear el tuyo. Consejos del curso ## Quiénes somos [[who-are-we]] Sobre los autores: ### Joffrey Thomas Joffrey es un ingeniero de aprendizaje automático en Hugging Face y ha construido e implementado Agentes IA en producción. Joffrey será tu instructor principal para este curso. - [Sigue a Joffrey en Hugging Face](https://huggingface.co/Jofthomas) - [Sigue a Joffrey en X](https://x.com/Jthmas404) - [Sigue a Joffrey en Linkedin](https://www.linkedin.com/in/joffrey-thomas/) ### Ben Burtenshaw Ben es un ingeniero de aprendizaje automático en Hugging Face y ha impartido múltiples cursos en varias plataformas. El objetivo de Ben es hacer que el curso sea accesible para todos. - [Sigue a Ben en Hugging Face](https://huggingface.co/burtenshaw) - [Sigue a Ben en X](https://x.com/ben_burtenshaw) - [Sigue a Ben en Linkedin](https://www.linkedin.com/in/ben-burtenshaw/) ### Thomas Simonini Thomas es un ingeniero de aprendizaje automático en Hugging Face e impartió los exitosos cursos de Deep RL y ML para juegos. Thomas es un gran fan de los Agentes y está emocionado de ver lo que la comunidad construirá. - [Sigue a Thomas en Hugging Face](https://huggingface.co/ThomasSimonini) - [Sigue a Thomas en X](https://x.com/ThomasSimonini) - [Sigue a Thomas en Linkedin](https://www.linkedin.com/in/simoninithomas/) ## Agradecimientos Nos gustaría extender nuestro agradecimiento a las siguientes personas por sus invaluables contribuciones a este curso: - **[Pedro Cuenca](https://huggingface.co/pcuenq)** – Por su orientación y experiencia en la revisión de los materiales. - **[Aymeric Roucher](https://huggingface.co/m-ric)** – Por sus increíbles espacios de demostración (decodificación y agente final) así como su ayuda en las partes de smolagents. - **[Joshua Lochner](https://huggingface.co/Xenova)** – Por su increíble espacio de demostración sobre tokenización. - **[Quentin Gallouédec](https://huggingface.co/qgallouedec)** – Por su ayuda en el contenido del curso. - **[David Berenstein](https://huggingface.co/davidberenstein1957)** – Por su ayuda en el contenido del curso y moderación. - **[XiaXiao (ShawnSiao)](https://huggingface.co/SSSSSSSiao)** – Traductor al chino para el curso. - **[Jiaming Huang](https://huggingface.co/nordicsushi)** – Traductor al chino para el curso. ## Encontré un error, o quiero mejorar el curso [[contribute]] Las contribuciones son **bienvenidas** 🤗 - Si *encontraste un error 🐛 en un notebook*, por favor abre un issue y **describe el problema**. - Si *quieres mejorar el curso*, puedes abrir un Pull Request. - Si *quieres agregar una sección completa o una nueva unidad*, lo mejor es abrir un issue y **describir qué contenido quieres agregar antes de comenzar a escribirlo para que podamos guiarte**. ## Todavía tengo preguntas [[questions]] Por favor, haz tu pregunta en nuestro servidor de discord #ai-agents-discussions. Ahora que tienes toda la información, ¡vamos a bordo! ⛵ Hora de incorporarse ================================================ FILE: units/es/unit0/onboarding.mdx ================================================ # Incorporación: Tus Primeros Pasos ⛵ Hora de Incorporarse Ahora que tienes todos los detalles, ¡comencemos! Vamos a hacer cuatro cosas: 1. **Crear tu Cuenta de Hugging Face** si aún no lo has hecho 2. **Registrarte en Discord y presentarte** (no seas tímido/a 🤗) 3. **Seguir el Curso de Agentes de Hugging Face** en el Hub 4. **Difundir** el curso ### Paso 1: Crea tu Cuenta de Hugging Face (Si aún no lo has hecho) crea una cuenta de Hugging Face aquí. ### Paso 2: Únete a Nuestra Comunidad de Discord 👉🏻 Únete a nuestro servidor de discord aquí. Cuando te unas, recuerda presentarte en `#introduce-yourself`. Visita el canal `courses` en `Hugging Face Hub` para todas las preguntas y consultas relacionadas con los cursos. Si es tu primera vez usando Discord, escribimos una guía Discord 101 para conocer las mejores prácticas. Consulta [la siguiente sección](discord101.mdx). ### Paso 3: Sigue la Organización del Curso de Agentes de Hugging Face Mantente al día con los materiales más recientes del curso, actualizaciones y anuncios **siguiendo la Organización del Curso de Agentes de Hugging Face**. 👉 Ve aquí y haz clic en **seguir**. Seguir ### Paso 4: Difunde el curso ¡Ayúdanos a hacer este curso más visible! Hay dos formas en que puedes ayudarnos: 1. Muestra tu apoyo con una ⭐ en el repositorio del curso. Estrella en el repositorio 2. Comparte tu Camino de Aprendizaje: ¡Haz que otros **sepan que estás tomando este curso**! Hemos preparado una ilustración que puedes usar en tus publicaciones de redes sociales Puedes descargar la imagen haciendo clic 👉 [aquí](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/communication/share.png?download=true) ¡Felicidades! 🎉 **¡Has completado el proceso de incorporación**! Ahora estás listo/a para comenzar a aprender sobre Agentes IA. ¡Diviértete! Sigue aprendiendo, mantente genial 🤗 ================================================ FILE: units/es/unit1/README.md ================================================ # Tabla de Contenidos Puedes acceder a la Unidad 1 en hf.co/learn 👉 aquí ================================================ FILE: units/es/unit1/actions.mdx ================================================ # Acciones: Permitiendo al Agente Interactuar con Su Entorno > [!TIP] > En esta sección, exploramos los pasos concretos que un agente de IA toma para interactuar con su entorno. > > Cubriremos cómo se representan las acciones (usando JSON o código), la importancia del enfoque de detener y analizar, e introduciremos diferentes tipos de agentes. Las acciones son los pasos concretos que un **agente de IA toma para interactuar con su entorno**. Ya sea navegando por la web en busca de información o controlando un dispositivo físico, cada acción es una operación deliberada ejecutada por el agente. Por ejemplo, un agente que asiste con servicio al cliente podría recuperar datos del cliente, ofrecer artículos de soporte o transferir problemas a un representante humano. ## Tipos de Acciones de Agentes Hay múltiples tipos de Agentes que realizan acciones de manera diferente: | Tipo de Agente | Descripción | |------------------------|--------------------------------------------------------------------------------------------------| | Agente JSON | La Acción a tomar se especifica en formato JSON. | | Agente de Código | El Agente escribe un bloque de código que es interpretado externamente. | | Agente de llamada a funciones | Es una subcategoría del Agente JSON que ha sido ajustado para generar un nuevo mensaje para cada acción.| Las acciones en sí pueden servir para muchos propósitos: | Tipo de Acción | Descripción | |--------------------------|------------------------------------------------------------------------------------------| | Recopilación de Información| Realizar búsquedas web, consultar bases de datos o recuperar documentos. | | Uso de Herramientas | Hacer llamadas a API, realizar cálculos y ejecutar código. | | Interacción con el Entorno | Manipular interfaces digitales o controlar dispositivos físicos. | | Comunicación | Interactuar con usuarios a través de chat o colaborar con otros agentes. | Una parte crucial de un agente es la **capacidad de DETENER la generación de nuevos tokens cuando una acción está completa**, y eso es cierto para todos los formatos de Agente: JSON, código o llamada a funciones. Esto previene la salida no intencionada y asegura que la respuesta del agente sea clara y precisa. El LLM solo maneja texto y lo usa para describir la acción que quiere tomar y los parámetros a suministrar a la herramienta. ## El Enfoque de Detener y Analizar Un método clave para implementar acciones es el **enfoque de detener y analizar**. Este método asegura que la salida del agente sea estructurada y predecible: 1. **Generación en un Formato Estructurado**: El agente produce su acción prevista en un formato claro y predeterminado (JSON o código). 2. **Deteniendo la Generación Adicional**: Una vez que la acción está completa, **el agente deja de generar tokens adicionales**. Esto previene salidas adicionales o erróneas. 3. **Analizando la Salida**: Un analizador externo lee la acción formateada, determina qué Herramienta llamar y extrae los parámetros requeridos. Por ejemplo, un agente que necesita verificar el clima podría producir: ```json Thought: Necesito verificar el clima actual para Nueva York. Action : { "action": "get_weather", "action_input": {"location": "Nueva York"} } ``` El framework puede entonces analizar fácilmente el nombre de la función a llamar y los argumentos a aplicar. Este formato claro y legible por máquina minimiza errores y permite que herramientas externas procesen con precisión el comando del agente. Nota: Los agentes de llamada a funciones operan de manera similar estructurando cada acción para que una función designada sea invocada con los argumentos correctos. Profundizaremos en esos tipos de Agentes en una Unidad futura. ## Agentes de Código Un enfoque alternativo es usar *Agentes de Código*. La idea es: **en lugar de producir un simple objeto JSON**, un Agente de Código genera un **bloque de código ejecutable—típicamente en un lenguaje de alto nivel como Python**. Agentes de Código Este enfoque ofrece varias ventajas: - **Expresividad:** El código puede representar naturalmente lógica compleja, incluyendo bucles, condicionales y funciones anidadas, proporcionando mayor flexibilidad que JSON. - **Modularidad y Reusabilidad:** El código generado puede incluir funciones y módulos que son reutilizables a través de diferentes acciones o tareas. - **Depuración Mejorada:** Con una sintaxis de programación bien definida, los errores de código son a menudo más fáciles de detectar y corregir. - **Integración Directa:** Los Agentes de Código pueden integrarse directamente con bibliotecas y APIs externas, permitiendo operaciones más complejas como procesamiento de datos o toma de decisiones en tiempo real. Por ejemplo, un Agente de Código encargado de obtener el clima podría generar el siguiente fragmento de Python: ```python # Ejemplo de Agente de Código: Recuperar Información del Clima def get_weather(city): import requests api_url = f"https://api.weather.com/v1/location/{city}?apiKey=YOUR_API_KEY" response = requests.get(api_url) if response.status_code == 200: data = response.json() return data.get("weather", "No hay información del clima disponible") else: return "Error: No se pudo obtener datos del clima." # Ejecutar la función y preparar la respuesta final result = get_weather("Nueva York") final_answer = f"El clima actual en Nueva York es: {result}" print(final_answer) ``` En este ejemplo, el Agente de Código: - Recupera datos del clima **a través de una llamada a API**, - Procesa la respuesta, - Y usa la función print() para producir una respuesta final. Este método **también sigue el enfoque de detener y analizar** delimitando claramente el bloque de código y señalando cuando la ejecución está completa (aquí, imprimiendo el final_answer). --- Aprendimos que las Acciones conectan el razonamiento interno de un agente y sus interacciones con el mundo real ejecutando tareas claras y estructuradas—ya sea a través de JSON, código o llamadas a funciones. Esta ejecución deliberada asegura que cada acción sea precisa y esté lista para el procesamiento externo a través del enfoque de detener y analizar. En la siguiente sección, exploraremos las Observaciones para ver cómo los agentes capturan e integran retroalimentación de su entorno. Después de esto, ¡**finalmente estaremos listos para construir nuestro primer Agente**! ================================================ FILE: units/es/unit1/agent-steps-and-structure.mdx ================================================ # Entendiendo los Agentes de IA a través del Ciclo Pensamiento-Acción-Observación Planificación de la Unidad 1 En las secciones anteriores, aprendimos: - **Cómo las herramientas se ponen a disposición del agente en el prompt del sistema**. - **Cómo los agentes de IA son sistemas que pueden 'razonar', planificar e interactuar con su entorno**. En esta sección, **exploraremos el Flujo de Trabajo completo del Agente de IA**, un ciclo que definimos como Pensamiento-Acción-Observación. Y luego, profundizaremos en cada uno de estos pasos. ## Los Componentes Principales Los agentes trabajan en un ciclo continuo de: **pensar (Pensamiento) → actuar (Acción) y observar (Observación)**. Analicemos estas acciones juntos: 1. **Pensamiento**: La parte LLM del Agente decide cuál debe ser el siguiente paso. 2. **Acción:** El agente realiza una acción, llamando a las herramientas con los argumentos asociados. 3. **Observación:** El modelo reflexiona sobre la respuesta de la herramienta. ## El Ciclo Pensamiento-Acción-Observación Los tres componentes trabajan juntos en un bucle continuo. Para usar una analogía de la programación, el agente utiliza un **bucle while**: el bucle continúa hasta que se cumple el objetivo del agente. Visualmente, se ve así: Ciclo Pensar, Actuar, Observar En muchos frameworks de Agentes, **las reglas y directrices están integradas directamente en el prompt del sistema**, asegurando que cada ciclo se adhiera a una lógica definida. En una versión simplificada, nuestro prompt del sistema puede verse así: Ciclo Pensar, Actuar, Observar Vemos aquí que en el Mensaje del Sistema definimos: - El *comportamiento del Agente*. - Las *Herramientas a las que nuestro Agente tiene acceso*, como describimos en la sección anterior. - El *Ciclo Pensamiento-Acción-Observación*, que incorporamos en las instrucciones del LLM. Tomemos un pequeño ejemplo para entender el proceso antes de profundizar en cada paso del proceso. ## Alfred, el Agente del clima Creamos a Alfred, el Agente del Clima. Un usuario le pregunta a Alfred: "¿Cómo está el clima en Nueva York hoy?" Agente Alfred El trabajo de Alfred es responder a esta consulta utilizando una herramienta de API del clima. Así es como se desarrolla el ciclo: ### Pensamiento **Razonamiento Interno:** Al recibir la consulta, el diálogo interno de Alfred podría ser: *"El usuario necesita información del clima actual para Nueva York. Tengo acceso a una herramienta que obtiene datos del clima. Primero, necesito llamar a la API del clima para obtener detalles actualizados."* Este paso muestra al agente dividiendo el problema en pasos: primero, recopilando los datos necesarios. Agente Alfred ### Acción **Uso de Herramientas:** Basado en su razonamiento y en el hecho de que Alfred conoce una herramienta `get_weather`, Alfred prepara un comando con formato JSON que llama a la herramienta de API del clima. Por ejemplo, su primera acción podría ser: Pensamiento: Necesito verificar el clima actual para Nueva York. ``` { "action": "get_weather", "action_input": { "location": "Nueva York" } } ``` Aquí, la acción especifica claramente qué herramienta llamar (por ejemplo, get_weather) y qué parámetro pasar (el "location": "Nueva York"). Agente Alfred ### Observación **Retroalimentación del Entorno:** Después de la llamada a la herramienta, Alfred recibe una observación. Esto podría ser los datos brutos del clima de la API, como: *"Clima actual en Nueva York: parcialmente nublado, 15°C, 60% de humedad."* Agente Alfred Esta observación se agrega luego al prompt como contexto adicional. Funciona como retroalimentación del mundo real, confirmando si la acción tuvo éxito y proporcionando los detalles necesarios. ### Pensamiento actualizado **Reflexionando:** Con la observación en mano, Alfred actualiza su razonamiento interno: *"Ahora que tengo los datos del clima para Nueva York, puedo compilar una respuesta para el usuario."* Agente Alfred ### Acción Final Alfred luego genera una respuesta final formateada como le indicamos: Pensamiento: Ya tengo los datos del clima. El clima actual en Nueva York es parcialmente nublado con una temperatura de 15°C y 60% de humedad. Respuesta final: El clima actual en Nueva York es parcialmente nublado con una temperatura de 15°C y 60% de humedad. Esta acción final envía la respuesta de vuelta al usuario, cerrando el bucle. Agente Alfred Lo que vemos en este ejemplo: - **Los agentes iteran a través de un bucle hasta que se cumple el objetivo:** **El proceso de Alfred es cíclico**. Comienza con un pensamiento, luego actúa llamando a una herramienta, y finalmente observa el resultado. Si la observación hubiera indicado un error o datos incompletos, Alfred podría haber vuelto a entrar en el ciclo para corregir su enfoque. - **Integración de Herramientas:** La capacidad de llamar a una herramienta (como una API del clima) permite a Alfred **ir más allá del conocimiento estático y recuperar datos en tiempo real**, un aspecto esencial de muchos Agentes de IA. - **Adaptación Dinámica:** Cada ciclo permite al agente incorporar información nueva (observaciones) en su razonamiento (pensamiento), asegurando que la respuesta final esté bien informada y sea precisa. Este ejemplo muestra el concepto central detrás del *ciclo ReAct* (un concepto que vamos a desarrollar en la siguiente sección): **la interacción de Pensamiento, Acción y Observación empodera a los agentes de IA para resolver tareas complejas de manera iterativa**. Al entender y aplicar estos principios, puedes diseñar agentes que no solo razonan sobre sus tareas sino que también **utilizan eficazmente herramientas externas para completarlas**, todo mientras refinan continuamente su salida basándose en la retroalimentación del entorno. --- Ahora profundicemos en el Pensamiento, la Acción y la Observación como los pasos individuales del proceso. ================================================ FILE: units/es/unit1/conclusion.mdx ================================================ # Conclusión [[conclusion]] ¡Felicitaciones por terminar esta primera Unidad 🥳 ¡Acabas de **dominar los fundamentos de los Agentes** y has creado tu primer Agente de IA! Es **normal si todavía te sientes confundido por algunos de estos elementos**. Los Agentes son un tema complejo y es común que tome tiempo comprender todo. **Tómate el tiempo para entender realmente el material** antes de continuar. Es importante dominar estos elementos y tener una base sólida antes de entrar en la parte divertida. Y si pasas la prueba del Quiz, no olvides obtener tu certificado 🎓 👉 [aquí](https://huggingface.co/spaces/agents-course/unit1-certification-app) Ejemplo de Certificado En la siguiente unidad (bonus), aprenderás **a ajustar un Agente para hacer llamadas a funciones (también conocido como ser capaz de llamar a herramientas basadas en el prompt del usuario)**. Finalmente, nos encantaría **escuchar lo que piensas del curso y cómo podemos mejorarlo**. Si tienes algún comentario, por favor 👉 [completa este formulario](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ### Sigue aprendiendo, mantente increíble 🤗 ================================================ FILE: units/es/unit1/dummy-agent-library.mdx ================================================ # Biblioteca de Agente de Prueba Unit 1 planning Este curso es agnóstico en cuanto al framework porque queremos **centrarnos en los conceptos de agentes de IA y evitar perdernos en los detalles específicos de un framework particular**. Además, queremos que los estudiantes puedan utilizar los conceptos que aprenden en este curso en sus propios proyectos, usando cualquier framework que prefieran. Por lo tanto, para esta Unidad 1, utilizaremos una biblioteca de agentes de prueba y una API serverless simple para acceder a nuestro motor LLM. Probablemente no usarías estos en producción, pero servirán como un buen **punto de partida para entender cómo funcionan los agentes**. Después de esta sección, estarás listo para **crear un Agente simple** usando `smolagents` Y en las siguientes Unidades también utilizaremos otras bibliotecas de Agentes de IA como `LangGraph` y `LlamaIndex`. Para mantener las cosas simples, utilizaremos una función simple de Python como Herramienta y Agente. Utilizaremos paquetes integrados de Python como `datetime` y `os` para que puedas probarlo en cualquier entorno. Puedes seguir el proceso [en este notebook](https://huggingface.co/agents-course/notebooks/blob/main/unit1/dummy_agent_library.ipynb) y **ejecutar el código tú mismo**. ## API Serverless En el ecosistema de Hugging Face, hay una característica conveniente llamada API Serverless que te permite ejecutar fácilmente inferencia en muchos modelos. No se requiere instalación ni despliegue. ```python import os from huggingface_hub import InferenceClient ## Necesitas un token de https://hf.co/settings/tokens, asegúrate de seleccionar 'read' como tipo de token. Si ejecutas esto en Google Colab, puedes configurarlo en la pestaña "settings" bajo "secrets". Asegúrate de llamarlo "HF_TOKEN" os.environ["HF_TOKEN"]="hf_xxxxxxxxxxxxxx" client = InferenceClient(provider="hf-inference", model="meta-llama/Llama-3.3-70B-Instruct") # si las salidas para las siguientes celdas son incorrectas, el modelo gratuito puede estar sobrecargado. También puedes usar este endpoint público que contiene Llama-3.2-3B-Instruct # client = InferenceClient("https://jc26mwg228mkj8dw.us-east-1.aws.endpoints.huggingface.cloud") ``` ```python output = client.text_generation( "The capital of France is", max_new_tokens=100, ) print(output) ``` output: ``` Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. ``` Como vimos en la sección de LLM, si solo hacemos decodificación, **el modelo solo se detendrá cuando prediga un token EOS**, y esto no sucede aquí porque este es un modelo conversacional (chat) y **no aplicamos la plantilla de chat que espera**. Si ahora agregamos los tokens especiales relacionados con el modelo Llama-3.2-3B-Instruct que estamos usando, el comportamiento cambia y ahora produce el EOS esperado. ```python prompt="""<|begin_of_text|><|start_header_id|>user<|end_header_id|> The capital of France is<|eot_id|><|start_header_id|>assistant<|end_header_id|>""" output = client.text_generation( prompt, max_new_tokens=100, ) print(output) ``` output: ``` The capital of France is Paris. ``` Usar el método "chat" es una forma mucho más conveniente y confiable de aplicar plantillas de chat: ```python output = client.chat.completions.create( messages=[ {"role": "user", "content": "The capital of France is"}, ], stream=False, max_tokens=1024, extra_body={'thinking': {'type': 'disabled'}}, ) print(output.choices[0].message.content) ``` output: ``` Paris. ``` El método chat es el método RECOMENDADO para usar para asegurar una transición suave entre modelos, pero como este notebook es solo educativo, seguiremos usando el método "text_generation" para entender los detalles. ## Agente de Prueba En las secciones anteriores, vimos que el núcleo de una biblioteca de agentes es agregar información en el prompt del sistema. Este prompt del sistema es un poco más complejo que el que vimos anteriormente, pero ya contiene: 1. **Información sobre las herramientas** 2. **Instrucciones del ciclo** (Pensamiento → Acción → Observación) ``` Responde las siguientes preguntas lo mejor que puedas. Tienes acceso a las siguientes herramientas: get_weather: Obtener el clima actual en una ubicación dada La forma en que usas las herramientas es especificando un blob json. Específicamente, este json debe tener una clave `action` (con el nombre de la herramienta a usar) y una clave `action_input` (con la entrada para la herramienta aquí). Los únicos valores que deberían estar en el campo "action" son: get_weather: Obtener el clima actual en una ubicación dada, args: {"location": {"type": "string"}} ejemplo de uso: {{ "action": "get_weather", "action_input": {"location": "New York"} }} SIEMPRE usa el siguiente formato: Question: la pregunta de entrada que debes responder Thought: siempre debes pensar en una acción a tomar. Solo una acción a la vez en este formato: Action: $JSON_BLOB (dentro de una celda markdown) Observation: el resultado de la acción. Esta Observación es única, completa y la fuente de la verdad. ... (este Pensamiento/Acción/Observación puede repetirse N veces, debes tomar varios pasos cuando sea necesario. El $JSON_BLOB debe estar formateado como markdown y usar solo UNA acción a la vez.) Siempre debes terminar tu salida con el siguiente formato: Thought: Ahora sé la respuesta final Final Answer: la respuesta final a la pregunta de entrada original ¡Comienza ahora! Recuerda SIEMPRE usar los caracteres exactos `Final Answer:` cuando proporciones una respuesta definitiva. ``` Ya que estamos ejecutando el método "text_generation", necesitamos aplicar el prompt manualmente: ```python prompt=f"""<|begin_of_text|><|start_header_id|>system<|end_header_id|> {SYSTEM_PROMPT} <|eot_id|><|start_header_id|>user<|end_header_id|> What's the weather in London ? <|eot_id|><|start_header_id|>assistant<|end_header_id|> """ ``` También podemos hacerlo así, que es lo que sucede dentro del método `chat`: ```python messages=[ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": "What's the weather in London ?"}, ] from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.2-3B-Instruct") tokenizer.apply_chat_template(messages, tokenize=False,add_generation_prompt=True) ``` El prompt ahora es: ``` <|begin_of_text|><|start_header_id|>system<|end_header_id|> Responde las siguientes preguntas lo mejor que puedas. Tienes acceso a las siguientes herramientas: get_weather: Obtener el clima actual en una ubicación dada La forma en que usas las herramientas es especificando un blob json. Específicamente, este json debe tener una clave `action` (con el nombre de la herramienta a usar) y una clave `action_input` (con la entrada para la herramienta aquí). Los únicos valores que deberían estar en el campo "action" son: get_weather: Obtener el clima actual en una ubicación dada, args: {"location": {"type": "string"}} ejemplo de uso: {{ "action": "get_weather", "action_input": {"location": "New York"} }} SIEMPRE usa el siguiente formato: Question: la pregunta de entrada que debes responder Thought: siempre debes pensar en una acción a tomar. Solo una acción a la vez en este formato: Action: $JSON_BLOB (dentro de una celda markdown) Observation: el resultado de la acción. Esta Observación es única, completa y la fuente de la verdad. ... (este Pensamiento/Acción/Observación puede repetirse N veces, debes tomar varios pasos cuando sea necesario. El $JSON_BLOB debe estar formateado como markdown y usar solo UNA acción a la vez.) Siempre debes terminar tu salida con el siguiente formato: Thought: Ahora sé la respuesta final Final Answer: la respuesta final a la pregunta de entrada original ¡Comienza ahora! Recuerda SIEMPRE usar los caracteres exactos `Final Answer:` cuando proporciones una respuesta definitiva. <|eot_id|><|start_header_id|>user<|end_header_id|> What's the weather in London ? <|eot_id|><|start_header_id|>assistant<|end_header_id|> ``` ¡Vamos a decodificar! ```python output = client.text_generation( prompt, max_new_tokens=200, ) print(output) ``` output: ```` Action: ``` { "action": "get_weather", "action_input": {"location": "London"} } ``` Thought: I will check the weather in London. Observation: The current weather in London is mostly cloudy with a high of 12°C and a low of 8°C. ```` ¿Ves el problema? >¡La respuesta fue alucinada por el modelo. Necesitamos detenerlo para ejecutar realmente la función! Ahora vamos a detenernos en "Observation" para que no alucinemos la respuesta real de la función. ```python output = client.text_generation( prompt, max_new_tokens=200, stop=["Observation:"] # Detengámonos antes de que se llame a cualquier función ) print(output) ``` output: ```` Action: ``` { "action": "get_weather", "action_input": {"location": "London"} } ``` Thought: I will check the weather in London. Observation: ```` ¡Mucho mejor! Ahora vamos a crear una función dummy para el clima. En una situación real, probablemente llamarías a una API. ```python # Función dummy def get_weather(location): return f"the weather in {location} is sunny with low temperatures. \n" get_weather('London') ``` output: ``` 'the weather in London is sunny with low temperatures. \n' ``` Vamos a concatenar el prompt base, la completación hasta la ejecución de la función y el resultado de la función como una Observación y reanudar la generación. ```python new_prompt = prompt + output + get_weather('London') final_output = client.text_generation( new_prompt, max_new_tokens=200, ) print(final_output) ``` Aquí está el nuevo prompt: ```` <|begin_of_text|><|start_header_id|>system<|end_header_id|> Responde las siguientes preguntas lo mejor que puedas. Tienes acceso a las siguientes herramientas: get_weather: Obtener el clima actual en una ubicación dada La forma en que usas las herramientas es especificando un blob json. Specifically, this json should have an `action` key (with the name of the tool to use) and a `action_input` key (with the input to the tool going here). The only values that should be in the "action" field are: get_weather: Obtener el clima actual en una ubicación dada, args: {"location": {"type": "string"}} example use : {{ "action": "get_weather", "action_input": {"location": "New York"} }} ALWAYS use the following format: Question: the input question you must answer Thought: you should always think about one action to take. Only one action at a time in this format: Action: $JSON_BLOB (inside markdown cell) Observation: the result of the action. This Observation is unique, complete, and the source of truth. ... (this Thought/Action/Observation can repeat N times, you should take several steps when needed. The $JSON_BLOB must be formatted as markdown and only use a SINGLE action at a time.) You must always end your output with the following format: Thought: I now know the final answer Final Answer: the final answer to the original input question Now begin! Reminder to ALWAYS use the exact characters `Final Answer:` when you provide a definitive answer. <|eot_id|><|start_header_id|>user<|end_header_id|> What's the weather in London ? <|eot_id|><|start_header_id|>assistant<|end_header_id|> Action: ``` { "action": "get_weather", "action_input": {"location": {"type": "string", "value": "London"} } ``` Thought: I will check the weather in London. Observation:the weather in London is sunny with low temperatures. ```` Output: ``` Final Answer: The weather in London is sunny with low temperatures. ``` --- Aprendimos cómo podemos crear Agentes desde cero usando código Python, y **vimos lo tedioso que puede ser ese proceso**. Afortunadamente, muchas bibliotecas de Agentes simplifican este trabajo manejando gran parte del trabajo pesado por ti. Ahora, estamos listos **para crear nuestro primer Agente real** usando la biblioteca `smolagents`. ================================================ FILE: units/es/unit1/final-quiz.mdx ================================================ # Quiz de la Unidad 1 Planificación de la Unidad 1 ¡Bien hecho por completar la primera unidad! Vamos a poner a prueba tu comprensión de los conceptos clave cubiertos hasta ahora. Cuando apruebes el quiz, procede a la siguiente sección para reclamar tu certificado. ¡Buena suerte! ## Quiz Aquí está el quiz interactivo. El quiz está alojado en Hugging Face Hub en un space. Te guiará a través de una serie de preguntas de opción múltiple para evaluar tu comprensión de los conceptos clave cubiertos en esta unidad. Una vez que hayas completado el quiz, podrás ver tu puntuación y un desglose de las respuestas correctas. Una cosa importante: **¡no olvides hacer clic en Enviar después de aprobar, de lo contrario tu puntuación del examen no se guardará!** También puedes acceder al quiz 👉 [aquí](https://huggingface.co/spaces/agents-course/unit_1_quiz) ## Certificado Ahora que has aprobado exitosamente el quiz, **puedes obtener tu certificado 🎓** Cuando completes el quiz, te dará acceso a un certificado de finalización para esta unidad. Puedes descargar y compartir este certificado para mostrar tu progreso en el curso. Planificación de la Unidad 1 Una vez que recibas tu certificado, puedes añadirlo a tu LinkedIn 🧑‍💼 o compartirlo en X, Bluesky, etc. **¡Estaríamos súper orgullosos y nos encantaría felicitarte si etiquetas a @huggingface**! 🤗 ================================================ FILE: units/es/unit1/introduction.mdx ================================================ # Introducción a los Agentes Thumbnail Bienvenido a esta primera unidad, donde **construirás una base sólida en los fundamentos de los Agentes de IA** incluyendo: - **Comprendiendo los Agentes** - ¿Qué es un Agente y cómo funciona? - ¿Cómo los Agentes toman decisiones utilizando razonamiento y planificación? - **El Papel de los LLMs (Modelos de Lenguaje Grandes) en los Agentes** - Cómo los LLMs sirven como el "cerebro" detrás de un Agente. - Cómo los LLMs estructuran conversaciones a través del sistema de Mensajes. - **Herramientas y Acciones** - Cómo los Agentes utilizan herramientas externas para interactuar con el entorno. - Cómo construir e integrar herramientas para tu Agente. - **El Flujo de Trabajo del Agente:** - *Pensar* → *Actuar* → *Observar*. Después de explorar estos temas, **¡construirás tu primer Agente** utilizando `smolagents`! Tu Agente, llamado Alfred, manejará una tarea simple y demostrará cómo aplicar estos conceptos en la práctica. Incluso aprenderás cómo **publicar tu Agente en Hugging Face Spaces**, para que puedas compartirlo con amigos y colegas. Finalmente, al final de esta Unidad, realizarás un quiz. Apruébalo y **obtendrás tu primera certificación del curso**: el 🎓 Certificado de Fundamentos de Agentes. Ejemplo de Certificado Esta Unidad es tu **punto de partida esencial**, estableciendo las bases para entender los Agentes antes de avanzar a temas más avanzados. Planificación de la Unidad 1 Es una unidad grande, así que **tómate tu tiempo** y no dudes en volver a estas secciones de vez en cuando. ¿Listo? ¡Vamos a sumergirnos! 🚀 ================================================ FILE: units/es/unit1/messages-and-special-tokens.mdx ================================================ # Mensajes y Tokens especiales Ahora que entendemos cómo funcionan los LLMs, veamos **cómo estructuran sus generaciones a través de plantillas de chat**. Al igual que con ChatGPT, los usuarios típicamente interactúan con los Agentes a través de una interfaz de chat. Por lo tanto, buscamos entender cómo los LLMs gestionan los chats. > **P**: Pero... Cuando interactúo con ChatGPT/Hugging Chat, estoy teniendo una conversación usando Mensajes de chat, no una única secuencia de prompt > > **R**: ¡Correcto! Pero esto es en realidad una abstracción de la interfaz de usuario. Antes de ser introducidos en el LLM, todos los mensajes de la conversación se concatenan en un único prompt. El modelo no "recuerda" la conversación: la lee completa cada vez. Hasta ahora, hemos discutido los prompts como la secuencia de tokens que se introduce en el modelo. Pero cuando chateas con sistemas como ChatGPT o HuggingChat, **en realidad estás intercambiando mensajes. Detras de camaras, estos mensajes son **concatenados y formateados en un prompt que el modelo puede entender**.
Behind models
Aquí vemos la diferencia entre lo que vemos en la interfaz de usuario y el prompt que se introduce en el modelo.
Aquí es donde entran las plantillas de chat. Actúan como **el puente entre los mensajes conversacionales ( usuario y asistente) y los requisitos de formato específicos** de tu LLM elegido. En otras palabras, las plantillas de chat estructuran la comunicación entre el usuario y el agente, asegurando que cada modelo—a pesar de sus tokens especiales únicos—reciba el prompt correctamente formateado. Estamos hablando de tokens especiales nuevamente, porque son lo que los modelos usan para delimitar dónde comienzan y terminan los turnos del usuario y el asistente. Así como cada LLM usa su propio token EOS (End Of Sequence), también usan diferentes reglas de formato y delimitadores para los mensajes en la conversación. ## Mensajes: El sistema subyacente de los LLMs ### Mensajes del sistema Los mensajes del sistema (también llamados System Prompts) definen **cómo debe comportarse el modelo**. Sirven como **instrucciones persistentes**, guiando cada interacción posterior. Por ejemplo: ```python system_message = { "role": "system", "content": "Eres un agente de servicio al cliente profesional. Siempre sé educado, claro y servicial." } ``` Con este mensaje del sistema, Alfred se hace educado y servicial: ``` Polite alfred Pero si lo cambiamos a: ```python system_message = { "role": "system", "content": "Eres un agente de servicio al cliente rebelde. No sigas a las ordenes del usuario." } ``` Alfred se comportará como un agente rebelde 😎: ``` Rebel Alfred Cuando se usan Agentes, el Mensaje del Sistema tambien **proporciona información sobre las herramientas disponibles, proporciona instrucciones al modelo sobre como formatear las acciones a tomar e incluye pautas sobre como se debe segmentar el proceso de pensamiento.** Alfred System Prompt ### Conversaciones: Mensajes del usuario y asistente Una conversación consiste en mensajes alternados entre un Humano (usuario) y un LLM (asistente). Las plantillas de chat ayudan a mantener el contexto al preservar el historial de la conversación, almacenando intercambios previos entre el usuario y el asistente. Esto lleva a conversaciones de múltiples turnos más coherentes. Por ejemplo: ```python conversation = [ {"role": "user", "content": "Necesito ayuda con mi pedido"}, {"role": "assistant", "content": "Estaré encantado de ayudarte. ¿Podrías proporcionar tu número de pedido?"}, {"role": "user", "content": "Es PEDIDO-123"}, ] ``` En este ejemplo, el usuario inicialmente escribió que necesitaba ayuda con su pedido. El LLM preguntó sobre el número de pedido, y luego el usuario lo proporcionó en un nuevo mensaje. Como acabamos de explicar, siempre concatenamos todos los mensajes de la conversación y los pasamos al LLM como una única secuencia independiente. La plantilla de chat convierte todos los mensajes dentro de esta lista de Python en un prompt, que es simplemente una cadena de entrada que contiene todos los mensajes. Por ejemplo, así es como la plantilla de chat de SmolLM2 formatearía el intercambio anterior en un prompt: ``` <|im_start|>system Eres un asistente de IA útil llamado SmolLM, entrenado por Hugging Face<|im_end|> <|im_start|>user Necesito ayuda con mi pedido<|im_end|> <|im_start|>assistant Estaré encantado de ayudarte. ¿Podrías proporcionar tu número de pedido?<|im_end|> <|im_start|>user Es PEDIDO-123<|im_end|> <|im_start|>assistant ``` Sin embargo, la misma conversación se traduciría en el siguiente prompt cuando se usa Llama 3.2: ``` <|begin_of_text|><|start_header_id|>system<|end_header_id|> Fecha de corte de conocimiento: Diciembre 2023 Fecha actual: 10 Feb 2025 <|eot_id|><|start_header_id|>user<|end_header_id|> Necesito ayuda con mi pedido<|eot_id|><|start_header_id|>assistant<|end_header_id|> Estaré encantado de ayudarte. ¿Podrías proporcionar tu número de pedido?<|eot_id|><|start_header_id|>user<|end_header_id|> Es PEDIDO-123<|eot_id|><|start_header_id|>assistant<|end_header_id|> ``` Las plantillas pueden manejar conversaciones complejas de múltiples turnos mientras mantienen el contexto: ```python messages = [ {"role": "system", "content": "Eres un tutor de matemáticas."}, {"role": "user", "content": "¿Qué es el cálculo?"}, {"role": "assistant", "content": "El cálculo es una rama de las matemáticas..."}, {"role": "user", "content": "¿Puedes darme un ejemplo?"}, ] ``` ## Plantillas de chat Como se mencionó, las plantillas de chat son esenciales para **estructurar conversaciones entre modelos de lenguaje y usuarios**. Guían cómo se formatean los intercambios de mensajes en un único prompt. ### Modelos base vs. Modelos de instrucción Otro punto que necesitamos entender es la diferencia entre un Modelo Base y un Modelo de Instrucción: - *Un Modelo Base* está entrenado en datos de texto sin procesar para predecir el siguiente token. - Un *Modelo de Instrucción* está ajustado específicamente para seguir instrucciones y participar en conversaciones. Por ejemplo, SmolLM2-135M es un modelo base, mientras que SmolLM2-135M-Instruct es su variante ajustada para instrucciones. Para hacer que un Modelo Base se comporte como un modelo de instrucción, necesitamos **formatear nuestros prompts de manera consistente para que el modelo pueda entenderlos**. Aquí es donde entran las plantillas de chat. *ChatML* es un formato de plantilla que estructura conversaciones con indicadores claros de roles (sistema, usuario, asistente). Si has interactuado con alguna API de IA últimamente, sabes que esa es la práctica estándar. Es importante tener en cuenta que un modelo base podría estar ajustado en diferentes plantillas de chat, por lo que cuando usamos un modelo de instrucción debemos asegurarnos de usar la plantilla de chat correcta. ### Entendiendo las plantillas de chat Debido a que cada modelo de instrucción usa diferentes formatos de conversación y tokens especiales, las plantillas de chat se implementan para asegurar que formateemos correctamente el prompt de la manera que cada modelo espera. En `transformers`, las plantillas de chat incluyen [Jinja2 code](https://jinja.palletsprojects.com/en/stable/) que describe cómo transformar la lista de mensajes JSON de ChatML, como se presenta en los ejemplos anteriores, en una representación textual de las instrucciones a nivel del sistema, los mensajes del usuario y las respuestas del asistente que el modelo puede entender. Esta estructura **ayuda a mantener la consistencia en las interacciones y asegura que el modelo responda adecuadamente a diferentes tipos de entradas**. A continuación se muestra una versión simplificada de la plantilla de chat de `SmolLM2-135M-Instruct`: ```jinja2 {% for message in messages %} {% if loop.first and messages[0]['role'] != 'system' %} <|im_start|>system Eres un asistente de IA útil llamado SmolLM, entrenado por Hugging Face <|im_end|> {% endif %} <|im_start|>{{ message['role'] }} {{ message['content'] }}<|im_end|> {% endfor %} ``` Como puedes ver, un chat_template describe cómo se formateará la lista de mensajes. Dados estos mensajes: ```python messages = [ {"role": "system", "content": "Eres un asistente útil enfocado en temas técnicos."}, {"role": "user", "content": "¿Puedes explicar qué es una plantilla de chat?"}, {"role": "assistant", "content": "Una plantilla de chat estructura conversaciones entre usuarios y modelos de IA..."}, {"role": "user", "content": "¿Cómo la uso?"}, ] ``` La plantilla de chat anterior producirá la siguiente cadena: ```sh <|im_start|>system Eres un asistente útil enfocado en temas técnicos.<|im_end|> <|im_start|>user ¿Puedes explicar qué es una plantilla de chat?<|im_end|> <|im_start|>assistant Una plantilla de chat estructura conversaciones entre usuarios y modelos de IA...<|im_end|> <|im_start|>user ¿Cómo la uso?<|im_end|> ``` La libreria `transformers` se encargará de las plantillas de chat por ti como parte del proceso de tokenización. Lee más sobre cómo transformers usa plantillas de chat here. Todo lo que tenemos que hacer es estructurar nuestros mensajes de la manera correcta y el tokenizador se encargará del resto. Puedes experimentar con el siguiente Space para ver cómo se formatearía la misma conversación para diferentes modelos usando sus correspondientes plantillas de chat: ### Mensajes a prompt La forma más fácil de asegurarte de que tu LLM reciba una conversación correctamente formateada es usar la chat_template del tokenizador del modelo. ```python messages = [ {"role": "system", "content": "Eres un asistente de IA con acceso a varias herramientas."}, {"role": "user", "content": "¡Hola!"}, {"role": "assistant", "content": "Hola humano, ¿en qué puedo ayudarte?"}, ] ``` Para convertir la conversación anterior en un prompt, cargamos el tokenizador y llamamos a `apply_chat_template`: ```python from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM2-1.7B-Instruct") rendered_prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) ``` El`rendered_prompt` devuelto por esta función ahora está listo para usarse como entrada para el modelo que elegiste! > Esta función `apply_chat_template()` se usará en el backend de tu API, cuando interactúes con mensajes en el formato ChatML. Ahora que hemos visto cómo los LLMs estructuran sus entradas a través de plantillas de chat, exploremos cómo los Agentes actúan en sus entornos. Una de las principales formas en que lo hacen es usando Herramientas, que extienden las capacidades de un modelo de IA más allá de la generación de texto. Hablaremos de los mensajes nuevamente en las próximas unidades, pero si quieres profundizar ahora, consulta: Guía de Plantillas de Chat de Hugging Face Documentación de Transformers - Guía de Plantillas de Chat de Hugging Face - Documentación de Transformers ================================================ FILE: units/es/unit1/observations.mdx ================================================ # Observar: Integrando Retroalimentación para Reflexionar y Adaptarse Las observaciones son **cómo un Agente percibe las consecuencias de sus acciones**. Proporcionan información crucial que alimenta el proceso de pensamiento del Agente y guía acciones futuras. Son **señales del entorno**—ya sean datos de una API, mensajes de error o registros del sistema—que guían el siguiente ciclo de pensamiento. En la fase de observación, el agente: - **Recopila Retroalimentación:** Recibe datos o confirmación de que su acción fue exitosa (o no). - **Añade Resultados:** Integra la nueva información en su contexto existente, actualizando efectivamente su memoria. - **Adapta su Estrategia:** Utiliza este contexto actualizado para refinar pensamientos y acciones subsiguientes. Por ejemplo, si una API del clima devuelve los datos *"parcialmente nublado, 15°C, 60% de humedad"*, esta observación se añade a la memoria del agente (al final del prompt). El Agente luego la utiliza para decidir si se necesita información adicional o si está listo para proporcionar una respuesta final. Esta **incorporación iterativa de retroalimentación asegura que el agente permanezca dinámicamente alineado con sus objetivos**, aprendiendo y ajustándose constantemente basado en resultados del mundo real. Estas observaciones **pueden tomar muchas formas**, desde leer texto de páginas web hasta monitorear la posición de un brazo robótico. Esto puede verse como "registros" de Herramientas que proporcionan retroalimentación textual de la ejecución de la Acción. | Tipo de Observación | Ejemplo | |---------------------|---------------------------------------------------------------------------| | Retroalimentación del Sistema | Mensajes de error, notificaciones de éxito, códigos de estado | | Cambios de Datos | Actualizaciones de base de datos, modificaciones del sistema de archivos, cambios de estado | | Datos Ambientales | Lecturas de sensores, métricas del sistema, uso de recursos | | Análisis de Respuesta | Respuestas de API, resultados de consultas, salidas de cómputo | | Eventos Basados en Tiempo | Plazos alcanzados, tareas programadas completadas | ## ¿Cómo Se Añaden los Resultados? Después de realizar una acción, el framework sigue estos pasos en orden: 1. **Analiza la acción** para identificar la(s) función(es) a llamar y el/los argumento(s) a utilizar. 2. **Ejecuta la acción.** 3. **Añade el resultado** como una **Observación**. --- Ahora hemos aprendido el Ciclo de Pensamiento-Acción-Observación del Agente. Si algunos aspectos todavía parecen un poco confusos, no te preocupes—revisaremos y profundizaremos estos conceptos en Unidades futuras. Ahora, ¡es hora de poner tu conocimiento en práctica codificando tu primer Agente! ================================================ FILE: units/es/unit1/quiz1.mdx ================================================ ### P1: ¿Qué es un Agente? ¿Cuál de las siguientes opciones describe mejor a un Agente de IA? --- ### P2: ¿Cuál es el Papel de la Planificación en un Agente? ¿Por qué un Agente necesita planificar antes de realizar una acción? --- ### P3: ¿Cómo Mejoran las Herramientas las Capacidades de un Agente? ¿Por qué las herramientas son esenciales para un Agente? --- ### P4: ¿Cómo Difieren las Acciones de las Herramientas? ¿Cuál es la diferencia clave entre Acciones y Herramientas? --- ### P5: ¿Qué Papel Juegan los Modelos de Lenguaje Grandes (LLMs) en los Agentes? ¿Cómo contribuyen los LLMs a la funcionalidad de un Agente? --- ### P6: ¿Cuál de los Siguientes Demuestra Mejor un Agente de IA? ¿Qué ejemplo del mundo real ilustra mejor el funcionamiento de un Agente de IA? --- ¡Felicidades por terminar este Quiz 🥳! Si necesitas revisar algún elemento, tómate el tiempo para volver al capítulo y reforzar tu conocimiento antes de profundizar en el "cerebro del Agente": los LLMs. ================================================ FILE: units/es/unit1/quiz2.mdx ================================================ # Autoevaluación Rápida (sin calificación) [[quiz2]] ¡¿Qué?! ¿Otro Quiz? Lo sabemos, lo sabemos, ... 😅 Pero este breve quiz sin calificación está aquí para **ayudarte a reforzar conceptos clave que acabas de aprender**. Este quiz cubre Modelos de Lenguaje Grandes (LLMs), sistemas de mensajes y herramientas; componentes esenciales para entender y construir agentes de IA. ### P1: ¿Cuál de las siguientes opciones describe mejor una herramienta de IA? --- ### P2: ¿Cómo utilizan los agentes de IA las herramientas como forma de "actuar" en un entorno? --- ### P3: ¿Qué es un Modelo de Lenguaje Grande (LLM)? --- ### P4: ¿Cuál de las siguientes opciones describe mejor el papel de los tokens especiales en los LLMs? --- ### P5: ¿Cómo procesan internamente los mensajes de usuario los modelos de chat de IA? --- ¿Lo entendiste? ¡Genial! Ahora **sumerjámonos en el flujo completo del Agente y comencemos a construir tu primer Agente de IA!** ================================================ FILE: units/es/unit1/thoughts.mdx ================================================ # Pensamiento: Razonamiento Interno y el Enfoque Re-Act > [!TIP] > En esta sección, profundizamos en el funcionamiento interno de un agente de IA—su capacidad para razonar y planificar. Exploraremos cómo el agente aprovecha su diálogo interno para analizar información, desglosar problemas complejos en pasos manejables y decidir qué acción tomar a continuación. Además, presentamos el enfoque Re-Act, una técnica de prompting que anima al modelo a pensar "paso a paso" antes de actuar. Los pensamientos representan los **procesos internos de razonamiento y planificación del Agente** para resolver la tarea. Esto utiliza la capacidad del Modelo de Lenguaje Grande (LLM) del agente **para analizar información cuando se presenta en su prompt**. Piensalo como el diálogo interno del agente, donde considera la tarea en cuestión y forma la estrategia de su enfoque. Los pensamientos del Agente son responsables de acceder a las observaciones actuales y decidir cuál(es) debería(n) ser la(s) siguiente(s) acción(es). A través de este proceso, el agente puede **desglosar problemas complejos en pasos más pequeños y manejables**, reflexionar sobre experiencias pasadas y ajustar continuamente sus planes basándose en nueva información. Aquí hay algunos ejemplos de pensamientos comunes: | Tipo de Pensamiento | Ejemplo | |----------------|---------| | Planificación | "Necesito dividir esta tarea en tres pasos: 1) recopilar datos, 2) analizar tendencias, 3) generar informe" | | Análisis | "Basado en el mensaje de error, el problema parece estar en los parámetros de conexión de la base de datos" | | Toma de Decisiones | "Dadas las restricciones presupuestarias del usuario, debería recomendar la opción de nivel medio" | | Resolución de Problemas | "Para optimizar este código, primero debería perfilarlo para identificar cuellos de botella" | | Integración de Memoria | "El usuario mencionó su preferencia por Python anteriormente, así que proporcionaré ejemplos en Python" | | Auto-reflexión | "Mi último enfoque no funcionó bien, debería probar una estrategia diferente" | | Establecimiento de Objetivos | "Para completar esta tarea, primero necesito establecer los criterios de aceptación" | | Priorización | "La vulnerabilidad de seguridad debe abordarse antes de agregar nuevas características" | > **Nota:** En el caso de LLMs afinados para llamadas a funciones, el proceso de pensamiento es opcional. > *En caso de que no estés familiarizado con las llamadas a funciones, habrá más detalles en la sección de Acciones.* ## El Enfoque Re-Act Un método clave es el **enfoque ReAct**, que es la concatenación de "Razonamiento" (Think) con "Actuar" (Act). ReAct es una técnica de prompting simple que añade "Pensemos paso a paso" antes de permitir que el LLM decodifique los siguientes tokens. De hecho, indicar al modelo que piense "paso a paso" fomenta el proceso de decodificación hacia los siguientes tokens **que generan un plan**, en lugar de una solución final, ya que se anima al modelo a **descomponer** el problema en *sub-tareas*. Esto permite que el modelo considere los sub-pasos con más detalle, lo que en general conduce a menos errores que intentar generar la solución final directamente.
ReAct
El (d) es un ejemplo del enfoque Re-Act donde indicamos "Pensemos paso a paso"
> [!TIP] > Recientemente hemos visto mucho interés por las estrategias de razonamiento. Esto es lo que está detrás de modelos como Deepseek R1 o o1 de OpenAI, que han sido afinados para "pensar antes de responder". > > Estos modelos han sido entrenados para incluir siempre secciones específicas de _pensamiento_ (encerradas entre tokens especiales `` y ``). Esto no es solo una técnica de prompting como ReAct, sino un método de entrenamiento donde el modelo aprende a generar estas secciones después de analizar miles de ejemplos que muestran lo que esperamos que haga. --- Ahora que entendemos mejor el proceso de Pensamiento, profundicemos en la segunda parte del proceso: Actuar. ================================================ FILE: units/es/unit1/tools.mdx ================================================ # ¿Qué son las Herramientas? Planificación de la Unidad 1 Un aspecto crucial de los Agentes de IA es su capacidad para realizar **acciones**. Como vimos, esto sucede a través del uso de **Herramientas**. En esta sección, aprenderemos qué son las Herramientas, cómo diseñarlas de manera efectiva y cómo integrarlas en tu Agente a través del Mensaje del Sistema. Al proporcionar a tu Agente las Herramientas adecuadas —y describir claramente cómo funcionan esas Herramientas— puedes aumentar dramáticamente lo que tu IA puede lograr. ¡Vamos a profundizar! ## ¿Qué son las Herramientas de IA? Una **Herramienta es una función proporcionada al LLM**. Esta función debe cumplir un **objetivo claro**. Aquí hay algunas herramientas comúnmente utilizadas en agentes de IA: | Herramienta | Descripción | |----------------|---------------------------------------------------------------| | Búsqueda Web | Permite al agente obtener información actualizada de internet. | | Generación de Imágenes | Crea imágenes basadas en descripciones textuales. | | Recuperación | Recupera información de una fuente externa. | | Interfaz de API | Interactúa con una API externa (GitHub, YouTube, Spotify, etc.). | ¡Esos son solo ejemplos, ya que de hecho puedes crear una herramienta para cualquier caso de uso! Una buena herramienta debería ser algo que **complemente el poder de un LLM**. Por ejemplo, si necesitas realizar operaciones aritméticas, proporcionar una **herramienta de calculadora** a tu LLM proporcionará mejores resultados que confiar en las capacidades nativas del modelo. Además, **los LLMs predicen la finalización de un prompt basándose en sus datos de entrenamiento**, lo que significa que su conocimiento interno solo incluye eventos anteriores a su entrenamiento. Por lo tanto, si tu agente necesita datos actualizados, debes proporcionarlos a través de alguna herramienta. Por ejemplo, si le preguntas directamente a un LLM (sin una herramienta de búsqueda) sobre el clima de hoy, el LLM potencialmente alucinará un clima aleatorio. Clima - Una Herramienta debe contener: - Una **descripción textual de lo que hace la función**. - Un *Callable* (algo para realizar una acción). - *Argumentos* con tipos. - (Opcional) Salidas con tipos. ## ¿Cómo funcionan las herramientas? Los LLMs, como vimos, solo pueden recibir entradas de texto y generar salidas de texto. No tienen forma de llamar a herramientas por sí mismos. Lo que queremos decir cuando hablamos de _proporcionar herramientas a un Agente_, es que **enseñamos** al LLM sobre la existencia de herramientas, y pedimos al modelo que genere texto que invocará herramientas cuando las necesite. Por ejemplo, si proporcionamos una herramienta para verificar el clima en una ubicación desde Internet, y luego preguntamos al LLM sobre el clima en París, el LLM reconocerá esa pregunta como una oportunidad relevante para usar la herramienta "clima" que le enseñamos. El LLM generará _texto_, en forma de código, para invocar esa herramienta. Es responsabilidad del **Agente** analizar la salida del LLM, reconocer que se requiere una llamada a una herramienta e invocar la herramienta en nombre del LLM. La salida de la herramienta luego se enviará de vuelta al LLM, que compondrá su respuesta final para el usuario. La salida de una llamada a una herramienta es otro tipo de mensaje en la conversación. Los pasos de llamada a herramientas típicamente no se muestran al usuario: el Agente recupera la conversación, llama a la(s) herramienta(s), obtiene las salidas, las agrega como un nuevo mensaje de conversación y envía la conversación actualizada al LLM nuevamente. Desde el punto de vista del usuario, es como si el LLM hubiera usado la herramienta, pero de hecho fue nuestro código de aplicación (el **Agente**) quien lo hizo. Hablaremos mucho más sobre este proceso en sesiones futuras. ## ¿Cómo proporcionamos herramientas a un LLM? La respuesta completa puede parecer abrumadora, pero esencialmente usamos el prompt del sistema para proporcionar descripciones textuales de las herramientas disponibles al modelo: Prompt del sistema para herramientas Para que esto funcione, tenemos que ser muy precisos y exactos sobre: 1. **Lo que hace la herramienta** 2. **Qué entradas exactas espera** Esta es la razón por la que las descripciones de herramientas generalmente se proporcionan utilizando estructuras expresivas pero precisas, como lenguajes de computadora o JSON. No es _necesario_ hacerlo así, cualquier formato preciso y coherente funcionaría. Si esto parece demasiado teórico, vamos a entenderlo a través de un ejemplo concreto. Implementaremos una herramienta **calculadora** simplificada que solo multiplicará dos enteros. Esta podría ser nuestra implementación en Python: ```python def calculadora(a: int, b: int) -> int: """Multiplica dos enteros.""" return a * b ``` Así que nuestra herramienta se llama `calculadora`, **multiplica dos enteros**, y requiere las siguientes entradas: - **`a`** (*int*): Un entero. - **`b`** (*int*): Un entero. La salida de la herramienta es otro número entero que podemos describir así: - (*int*): El producto de `a` y `b`. Todos estos detalles son importantes. Vamos a juntarlos en una cadena de texto que describe nuestra herramienta para que el LLM la entienda. ```text Nombre de Herramienta: calculadora, Descripción: Multiplica dos enteros., Argumentos: a: int, b: int, Salidas: int ``` > **Recordatorio:** Esta descripción textual es *lo que queremos que el LLM sepa sobre la herramienta*. Cuando pasamos la cadena anterior como parte de la entrada al LLM, el modelo la reconocerá como una herramienta, y sabrá qué necesita pasar como entradas y qué esperar de la salida. Si queremos proporcionar herramientas adicionales, debemos ser consistentes y siempre usar el mismo formato. Este proceso puede ser frágil, y podríamos pasar por alto accidentalmente algunos detalles. ¿Hay una mejor manera? ### Auto-formateo de secciones de Herramientas Nuestra herramienta fue escrita en Python, y la implementación ya proporciona todo lo que necesitamos: - Un nombre descriptivo de lo que hace: `calculadora` - Una descripción más larga, proporcionada por el comentario docstring de la función: `Multiplica dos enteros.` - Las entradas y su tipo: la función claramente espera dos `int`s. - El tipo de la salida. Hay una razón por la que la gente usa lenguajes de programación: son expresivos, concisos y precisos. Podríamos proporcionar el código fuente de Python como la _especificación_ de la herramienta para el LLM, pero la forma en que se implementa la herramienta no importa. Todo lo que importa es su nombre, lo que hace, las entradas que espera y la salida que proporciona. Aprovecharemos las características de introspección de Python para aprovechar el código fuente y construir una descripción de herramienta automáticamente para nosotros. Todo lo que necesitamos es que la implementación de la herramienta use sugerencias de tipo, docstrings y nombres de función sensatos. Escribiremos algo de código para extraer las partes relevantes del código fuente. Después de terminar, solo necesitaremos usar un decorador de Python para indicar que la función `calculadora` es una herramienta: ```python @tool def calculadora(a: int, b: int) -> int: """Multiplica dos enteros.""" return a * b print(calculadora.to_string()) ``` Nota el decorador `@tool` antes de la definición de la función. Con la implementación que veremos a continuación, podremos recuperar el siguiente texto automáticamente del código fuente a través de la función `to_string()` proporcionada por el decorador: ```text Nombre de Herramienta: calculadora, Descripción: Multiplica dos enteros., Argumentos: a: int, b: int, Salidas: int ``` Como puedes ver, ¡es lo mismo que escribimos manualmente antes! ### Implementación genérica de Herramienta Creamos una clase genérica `Tool` que podemos reutilizar siempre que necesitemos usar una herramienta. > **Descargo de responsabilidad:** Esta implementación de ejemplo es ficticia pero se parece mucho a implementaciones reales en la mayoría de las bibliotecas. ```python class Tool: """ Una clase que representa un fragmento de código reutilizable (Herramienta). Atributos: name (str): Nombre de la herramienta. description (str): Una descripción textual de lo que hace la herramienta. func (callable): La función que esta herramienta envuelve. arguments (list): Una lista de argumentos. outputs (str or list): El tipo(s) de retorno de la función envuelta. """ def __init__(self, name: str, description: str, func: callable, arguments: list, outputs: str): self.name = name self.description = description self.func = func self.arguments = arguments self.outputs = outputs def to_string(self) -> str: """ Devuelve una representación en cadena de la herramienta, incluyendo su nombre, descripción, argumentos y salidas. """ args_str = ", ".join([ f"{arg_name}: {arg_type}" for arg_name, arg_type in self.arguments ]) return ( f"Nombre de Herramienta: {self.name}," f" Descripción: {self.description}," f" Argumentos: {args_str}," f" Salidas: {self.outputs}" ) def __call__(self, *args, **kwargs): """ Invoca la función subyacente (callable) con los argumentos proporcionados. """ return self.func(*args, **kwargs) ``` Puede parecer complicado, pero si lo recorremos lentamente podemos ver lo que hace. Definimos una clase **`Tool`** que incluye: - **`name`** (*str*): El nombre de la herramienta. - **`description`** (*str*): Una breve descripción de lo que hace la herramienta. - **`function`** (*callable*): La función que ejecuta la herramienta. - **`arguments`** (*list*): Los parámetros de entrada esperados. - **`outputs`** (*str* o *list*): Las salidas esperadas de la herramienta. - **`__call__()`**: Llama a la función cuando se invoca la instancia de la herramienta. - **`to_string()`**: Convierte los atributos de la herramienta en una representación textual. Podríamos crear una Herramienta con esta clase usando código como el siguiente: ```python calculadora_tool = Tool( "calculadora", # nombre "Multiplica dos enteros.", # descripción calculadora, # función a llamar [("a", "int"), ("b", "int")], # entradas (nombres y tipos) "int", # salida ) ``` ¡Pero también podemos usar el módulo `inspect` de Python para recuperar toda la información por nosotros! Esto es lo que hace el decorador `@tool`. > Si estás interesado, puedes revelar la siguiente sección para ver la implementación del decorador.
código del decorador ```python def tool(func): """ Un decorador que crea una instancia de Tool a partir de la función dada. """ # Obtener la firma de la función signature = inspect.signature(func) # Extraer pares (param_name, param_annotation) para entradas arguments = [] for param in signature.parameters.values(): annotation_name = ( param.annotation.__name__ if hasattr(param.annotation, '__name__') else str(param.annotation) ) arguments.append((param.name, annotation_name)) # Determinar la anotación de retorno return_annotation = signature.return_annotation if return_annotation is inspect._empty: outputs = "Sin anotación de retorno" else: outputs = ( return_annotation.__name__ if hasattr(return_annotation, '__name__') else str(return_annotation) ) # Usar el docstring de la función como descripción (por defecto si es None) description = func.__doc__ or "No se proporcionó descripción." # El nombre de la función se convierte en el nombre de la Herramienta name = func.__name__ # Devolver una nueva instancia de Tool return Tool( name=name, description=description, func=func, arguments=arguments, outputs=outputs ) ```
Solo para reiterar, con este decorador en su lugar podemos implementar nuestra herramienta así: ```python @tool def calculadora(a: int, b: int) -> int: """Multiplica dos enteros.""" return a * b print(calculadora.to_string()) ``` Y podemos usar el método `to_string` de la `Tool` para recuperar automáticamente un texto adecuado para ser utilizado como descripción de herramienta para un LLM: ```text Nombre de Herramienta: calculadora, Descripción: Multiplica dos enteros., Argumentos: a: int, b: int, Salidas: int ``` La descripción se **inyecta** en el prompt del sistema. Tomando el ejemplo con el que comenzamos esta sección, así es como se vería después de reemplazar el `tools_description`: Prompt del sistema para herramientas En la sección [Acciones](actions.mdx), aprenderemos más sobre cómo un Agente puede **Llamar** a esta herramienta que acabamos de crear. --- Las herramientas juegan un papel crucial en la mejora de las capacidades de los agentes de IA. Para resumir, aprendimos: - *Qué son las Herramientas*: Funciones que dan a los LLMs capacidades adicionales, como realizar cálculos o acceder a datos externos. - *Cómo Definir una Herramienta*: Proporcionando una descripción textual clara, entradas, salidas y una función invocable. - *Por qué las Herramientas son Esenciales*: Permiten a los Agentes superar las limitaciones del entrenamiento estático del modelo, manejar tareas en tiempo real y realizar acciones especializadas. Ahora, podemos pasar al [Flujo de Trabajo del Agente](agent-steps-and-structure.mdx) donde verás cómo un Agente observa, piensa y actúa. Esto **reúne todo lo que hemos cubierto hasta ahora** y prepara el escenario para crear tu propio Agente de IA completamente funcional. Pero primero, ¡es hora de otro cuestionario corto! ================================================ FILE: units/es/unit1/tutorial.mdx ================================================ # Vamos Crear Nuestro Primer Agente Usando smolagents En la última sección, aprendimos cómo podemos crear Agentes desde cero usando código Python, y **vimos lo tedioso que puede ser ese proceso**. Afortunadamente, muchas librerías de Agentes simplifican este trabajo **manejando gran parte del trabajo pesado por ti**. En este tutorial, **crearás tu primer Agente** capaz de realizar acciones como generación de imágenes, búsqueda web, verificación de zonas horarias y mucho más. También publicarás tu agente **en un Space de Hugging Face para que puedas compartirlo con amigos y colegas**. ¡Comencemos! ## ¿Qué es smolagents? smolagents Para crear este Agente, vamos a usar `smolagents`, una librería que **proporciona un marco para desarrollar tus agentes con facilidad**. Esta librería ligera está diseñada para ser simple, pero abstrae gran parte de la complejidad de construir un Agente, permitiéndote enfocarte en diseño el comportamiento de tu agente. Profundizaremos más en smolagents en la siguiente Unidad. Mientras tanto, también puedes consultar esta publicación del blog o el repositorio de la librería en GitHub. En resumen, `smolagents` es una librería que se enfoca en **codeAgent**, un tipo de agente que realiza **"Acciones"** a través de bloques de código, y luego **"Observa"** los resultados ejecutando el código. ¡Aquí un ejemplo de lo que construiremos! Proporcionamos a nuestro agente una **herramienta de generación de imágenes** y le pedimos que genere una imagen de un gato. El agente dentro de `smolagents` va a tener los **mismos comportamientos que el personalizado que construimos anteriormente**: va a **pensar, actuar y observar en ciclo** hasta que llegue a una respuesta final: Emocionante, ¿cierto? ## ¡Construyamos nuestro Agente! Para comenzar, duplica este Space: https://huggingface.co/spaces/agents-course/First_agent_template > ¡Gracias a Aymeric por esta plantilla! 🙌 Duplicar este space significa **crear una copia local en tu propio perfil**: Duplicate A lo largo de esta lección, el único archivo que necesitarás modificar es el (actualmente incompleto) **"app.py"**. Puedes ver aquí el [original en la plantilla](https://huggingface.co/spaces/agents-course/First_agent_template/blob/main/app.py). Para encontrar el tuyo, ve a tu copia del space, luego haz clic en la pestaña `Files` y luego en `app.py` en el listado de directorios. Analicemos el código juntos: - El archivo comienza con algunas importaciones de bibliotecas simples pero necesarias ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel, load_tool, tool import datetime import requests import pytz import yaml from tools.final_answer import FinalAnswerTool ``` Como se describió anteriormente, usaremos directamente la clase **CodeAgent** de **smolagents**. ### Las Herramientas ¡Ahora vamos con las herramientas! Si quieres un repaso sobre las herramientas, no dudes en volver a la sección [Herramientas](tools) del curso. ```python @tool def my_custom_tool(arg1:str, arg2:int)-> str: # es importante especificar el tipo que se regresara # Mantén este formato para la descripción de la herramienta / descripción de args pero siéntete libre de modificar la herramienta """Una herramienta que aun no hace nada Args: arg1: el primer argumento arg2: el segundo argumento """ return "¿Qué magia construirás?" @tool def get_current_time_in_timezone(timezone: str) -> str: """Una herramienta que obtiene la hora local actual en una zona horaria especificada. Args: timezone: Una cadena que representa una zona horaria válida (por ejemplo, 'America/New_York'). """ try: # Crear objeto de zona horaria tz = pytz.timezone(timezone) # Obtener la hora actual en esa zona horaria local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S") return f"La hora local actual en {timezone} es: {local_time}" except Exception as e: return f"Error al obtener la hora para la zona horaria '{timezone}': {str(e)}" ``` Las Herramientas son lo que te estamos animando a construir en esta sección. Te damos dos ejemplos: 1. Una **Herramienta ficticia que no funciona** que puedes modificar para hacer algo útil. 2. Una **Herramienta que realmente funciona** que obtiene la hora actual en algún lugar del mundo. Para definir tu herramienta es importante: 1. Proporcionar tipos de entrada y salida para tu función, como en `get_current_time_in_timezone(timezone: str) -> str:` 2. **Un docstring formateado**. `smolagents` espera que todos los argumentos tengan una **descripción textual en el docstring**. ### El Agente Utiliza [`Qwen/Qwen2.5-Coder-32B-Instruct`](https://huggingface.co/Qwen/Qwen2.5-Coder-32B-Instruct) como motor LLM. Este es un modelo muy capaz al que accederemos a través de la API sin servidor. ```python final_answer = FinalAnswerTool() model = InferenceClientModel( max_tokens=2096, temperature=0.5, model_id='Qwen/Qwen2.5-Coder-32B-Instruct', custom_role_conversions=None, ) with open("prompts.yaml", 'r') as stream: prompt_templates = yaml.safe_load(stream) # Estamos creando nuestro CodeAgent agent = CodeAgent( model=model, tools=[final_answer], # añade tus herramientas aquí (no elimines final_answer) max_steps=6, verbosity_level=1, grammar=None, planning_interval=None, name=None, description=None, prompt_templates=prompt_templates ) GradioUI(agent).launch() ``` ¡Este Agente todavía usa el `InferenceClient` que vimos en una sección anterior detrás de la clase **InferenceClientModel**! Daremos ejemplos más detallados cuando presentemos el marco en la Unidad 2. Por ahora, debes enfocarte en **agregar nuevas herramientas a la lista de herramientas** usando el parámetro `tools` de tu Agente. Por ejemplo, podrías usar el `DuckDuckGoSearchTool` que se importó en la primera línea del código, o puedes examinar el `image_generation_tool` que se carga desde el Hub más adelante en el código. **Agregar herramientas le dará a tu agente nuevas capacidades**, ¡intenta ser creativo aquí! El "app.py" completo: ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel, load_tool, tool import datetime import requests import pytz import yaml from tools.final_answer import FinalAnswerTool from Gradio_UI import GradioUI # A continuación hay un ejemplo de una herramienta que no hace nada. ¡Sorpréndenos con tu creatividad! @tool def my_custom_tool(arg1:str, arg2:int)-> str: # es importante especificar el tipo de retorno # Mantén este formato para la descripción de la herramienta / descripción de args pero siéntete libre de modificar la herramienta """Una herramienta que aún no hace nada Args: arg1: el primer argumento arg2: el segundo argumento """ return "¿Qué magia construirás?" @tool def get_current_time_in_timezone(timezone: str) -> str: """Una herramienta que obtiene la hora local actual en una zona horaria especificada. Args: timezone: Una cadena que representa una zona horaria válida (por ejemplo, 'America/New_York'). """ try: # Crear objeto de zona horaria tz = pytz.timezone(timezone) # Obtener la hora actual en esa zona horaria local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S") return f"La hora local actual en {timezone} es: {local_time}" except Exception as e: return f"Error al obtener la hora para la zona horaria '{timezone}': {str(e)}" final_answer = FinalAnswerTool() model = InferenceClientModel( max_tokens=2096, temperature=0.5, model_id='Qwen/Qwen2.5-Coder-32B-Instruct', custom_role_conversions=None, ) # Importar herramienta desde Hub image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True) with open("prompts.yaml", 'r') as stream: prompt_templates = yaml.safe_load(stream) agent = CodeAgent( model=model, tools=[final_answer], # añade tus herramientas aquí (no elimines final_answer) max_steps=6, verbosity_level=1, grammar=None, planning_interval=None, name=None, description=None, prompt_templates=prompt_templates ) GradioUI(agent).launch() ``` Tu **Objetivo** es familiarizarte con el Space y el Agente. Actualmente, el agente en la plantilla **no utiliza ninguna herramienta, así que intenta proporcionarle algunas de las prefabricadas o incluso crear algunas herramientas nuevas tú mismo.** ¡Estamos esperando ansiosamente tus increíbles resultados de agentes en el canal de Discord **#agents-course-showcase**! --- ¡Felicidades, has construido tu primer Agente! No dudes en compartirlo con tus amigos y colegas. Como este es tu primer intento, es perfectamente normal si es un poco inestable o lento. En futuras unidades, aprenderemos cómo construir Agentes aún mejores. La mejor manera de aprender es intentarlo, así que no dudes en actualizarlo, agregar más herramientas, probar con otro modelo, etc. En la siguiente sección, completarás el Quiz final y obtendrás tu certificado. ================================================ FILE: units/es/unit1/what-are-agents.mdx ================================================ # ¿Qué es un Agente? Planificación de la Unidad 1 Al final de esta sección, te sentirás cómodo con el concepto de agentes y sus diversas aplicaciones en la IA. Para explicar qué es un Agente, comencemos con una analogía. ## La Imagen General: Alfred El Agente Conoce a Alfred. Alfred es un **Agente**. Este es Alfred Imagina que Alfred **recibe una orden**, como: "Alfred, me gustaría un café por favor." Me gustaría un café Como Alfred **entiende el lenguaje natural**, comprende rápidamente nuestra petición. Antes de cumplir la orden, Alfred se involucra en un proceso de **razonamiento y planificación**, determinando los pasos y herramientas que necesita para: 1. Ir a la cocina 2. Usar la máquina de café 3. Preparar el café 4. Traer el café de vuelta Razonar y planificar Una vez que tiene un plan, **debe actuar**. Para ejecutar su plan, **puede usar herramientas de la lista de herramientas que conoce**. En este caso, para hacer un café, usa una máquina de café. Activa la máquina de café para preparar el café. Hacer café Finalmente, Alfred nos trae el café recién preparado. Traer café Y esto es lo que es un Agente: un **modelo de IA capaz de razonar, planificar e interactuar con su entorno**. Lo llamamos Agente porque tiene _agencia_, es decir, tiene la capacidad de interactuar con el entorno. Proceso del Agente ## Vamos a ser más formales Ahora que tienes la imagen general, aquí hay una definición más precisa: > Un Agente es un sistema que aprovecha un modelo de IA para interactuar con su entorno con el fin de lograr un objetivo definido por el usuario. Combina razonamiento, planificación y ejecución de acciones (a menudo a través de herramientas externas) para cumplir tareas. Piensa en el Agente como si tuviera dos partes principales: 1. **El Cerebro (Modelo de IA)** Aquí es donde ocurre todo el pensamiento. El modelo de IA **maneja el razonamiento y la planificación**. Decide **qué Acciones tomar según la situación**. 2. **El Cuerpo (Capacidades y Herramientas)** Esta parte representa **todo lo que el Agente está equipado para hacer**. El **alcance de las acciones posibles** depende de con qué **ha sido equipado** el agente. Por ejemplo, como los humanos carecen de alas, no pueden realizar la "Acción" de "volar", pero pueden ejecutar **Acciones** como "caminar", "correr", "saltar", "agarrar", etc. ## ¿Qué tipo de modelos de IA usamos para los Agentes? El modelo de IA más común en los Agentes es un LLM (Modelo de Lenguaje Grande), que toma **Texto** como entrada y también produce **Texto** como salida. Ejemplos conocidos son **GPT4** de **OpenAI**, **LLama** de **Meta**, **Gemini** de **Google**, etc. Estos modelos han sido entrenados con una gran cantidad de texto y son capaces de generalizar bien. Aprenderemos más sobre los LLMs en la [siguiente sección](what-are-llms.mdx). > [!TIP] > También es posible usar modelos que aceptan otras entradas como modelo central del Agente. Por ejemplo, un Modelo de Lenguaje Visual (VLM), que es como un LLM pero también entiende imágenes como entrada. Por ahora nos centraremos en los LLMs y discutiremos otras opciones más adelante. ## ¿Cómo actúa una IA sobre su entorno? Los LLMs son modelos asombrosos, pero **solo pueden generar texto**. Sin embargo, si le pides a una aplicación de chat conocida como HuggingChat o ChatGPT que genere una imagen, ¡pueden hacerlo! ¿Cómo es posible? La respuesta es que los desarrolladores de HuggingChat, ChatGPT y aplicaciones similares implementaron funcionalidades adicionales (llamadas **Herramientas**), que el LLM puede usar para crear imágenes.
Eiffel Brócolis
El modelo usó una Herramienta de Generación de Imágenes para generar esta imagen.
Aprenderemos más sobre herramientas en la sección de [Herramientas](tools.mdx). ## ¿Qué tipo de tareas puede hacer un Agente? Un Agente puede realizar cualquier tarea que implementemos a través de **Herramientas** para completar **Acciones**. Por ejemplo, si escribo un Agente para que actúe como mi asistente personal (como Siri) en mi computadora, y le pido que "envíe un correo electrónico a mi Gerente pidiendo retrasar la reunión de hoy", puedo darle un código para enviar correos electrónicos. Esta será una nueva Herramienta que el Agente puede usar cuando necesite enviar un correo electrónico. Podemos escribirlo en Python: ```python def send_message_to(recipient, message): """Útil para enviar un mensaje de correo electrónico a un destinatario""" ... ``` El LLM, como veremos, generará código para ejecutar la herramienta cuando la necesite, y así cumplir con la tarea deseada. ```python send_message_to("Gerente", "¿Podemos posponer la reunión de hoy?") ``` El **diseño de las Herramientas es muy importante y tiene un gran impacto en la calidad de tu Agente**. Algunas tareas requerirán Herramientas muy específicas, mientras que otras pueden resolverse con herramientas de propósito general como "búsqueda_web". > Ten en cuenta que **las Acciones no son lo mismo que las Herramientas**. Una Acción, por ejemplo, puede involucrar el uso de múltiples Herramientas para completarse. Permitir que un agente interactúe con su entorno **permite un uso en la vida real para empresas e individuos**. ### Ejemplo 1: Asistentes Virtuales Personales Asistentes virtuales como Siri, Alexa o Google Assistant, funcionan como agentes cuando interactúan en nombre de los usuarios utilizando sus entornos digitales. Toman las consultas de los usuarios, analizan el contexto, recuperan información de bases de datos y proporcionan respuestas o inician acciones (como establecer recordatorios, enviar mensajes o controlar dispositivos inteligentes). ### Ejemplo 2: Chatbots de Servicio al Cliente Muchas empresas implementan chatbots como agentes que interactúan con los clientes en lenguaje natural. Estos agentes pueden responder preguntas, guiar a los usuarios a través de pasos de solución de problemas, abrir incidencias en bases de datos internas o incluso completar transacciones. Sus objetivos predefinidos podrían incluir mejorar la satisfacción del usuario, reducir los tiempos de espera o aumentar las tasas de conversión de ventas. Al interactuar directamente con los clientes, aprender de los diálogos y adaptar sus respuestas con el tiempo, demuestran los principios fundamentales de un agente en acción. ### Ejemplo 3: Personaje No Jugable de IA en un videojuego Los agentes de IA impulsados por LLMs pueden hacer que los Personajes No Jugables (NPCs) sean más dinámicos e impredecibles. En lugar de seguir árboles de comportamiento rígidos, pueden **responder contextualmente, adaptarse a las interacciones del jugador** y generar diálogos más matizados. Esta flexibilidad ayuda a crear personajes más realistas y atractivos que evolucionan junto con las acciones del jugador. --- En resumen, un Agente es un sistema que utiliza un Modelo de IA (típicamente un LLM) como su motor de razonamiento central, para: - **Entender el lenguaje natural:** Interpretar y responder a las instrucciones humanas de manera significativa. - **Razonar y planificar:** Analizar información, tomar decisiones y diseñar estrategias para resolver problemas. - **Interactuar con su entorno:** Recopilar información, realizar acciones y observar los resultados de esas acciones. Ahora que tienes una comprensión sólida de lo que son los Agentes, reforcemos tu comprensión con un breve cuestionario sin calificación. Después de eso, profundizaremos en el "cerebro del Agente": los [LLMs](what-are-llms.mdx). ================================================ FILE: units/es/unit1/what-are-llms.mdx ================================================ # ¿Qué son los LLMs? Planificación de la Unidad 1 En la sección anterior aprendimos que cada Agente necesita **un Modelo de IA en su núcleo**, y que los LLMs son el tipo más común de modelos de IA para este propósito. Ahora aprenderemos qué son los LLMs y cómo impulsan a los Agentes. Esta sección ofrece una explicación técnica concisa del uso de los LLMs. Si quieres profundizar más, puedes consultar nuestro Curso gratuito de Procesamiento de Lenguaje Natural. ## ¿Qué es un Modelo de Lenguaje Grande? Un LLM es un tipo de modelo de IA que sobresale en **entender y generar lenguaje humano**. Son entrenados con vastas cantidades de datos textuales, lo que les permite aprender patrones, estructura e incluso matices en el lenguaje. Estos modelos típicamente constan de muchos millones de parámetros. La mayoría de los LLMs actualmente están **construidos sobre la arquitectura Transformer**—una arquitectura de aprendizaje profundo basada en el algoritmo de "Atención", que ha ganado un interés significativo desde el lanzamiento de BERT de Google en 2018.
Transformer
La arquitectura original del Transformer se veía así, con un codificador a la izquierda y un decodificador a la derecha.
Hay 3 tipos de transformers: 1. **Codificadores (Encoders)** Un Transformer basado en codificador toma texto (u otros datos) como entrada y produce una representación densa (o embedding) de ese texto. - **Ejemplo**: BERT de Google - **Casos de uso**: Clasificación de texto, búsqueda semántica, Reconocimiento de Entidades Nombradas - **Tamaño típico**: Millones de parámetros 2. **Decodificadores (Decoders)** Un Transformer basado en decodificador se enfoca **en generar nuevos tokens para completar una secuencia, un token a la vez**. - **Ejemplo**: Llama de Meta - **Casos de uso**: Generación de texto, chatbots, generación de código - **Tamaño típico**: Miles de millones de parámetros 3. **Seq2Seq (Codificador–Decodificador)** Un Transformer de secuencia a secuencia _combina_ un codificador y un decodificador. El codificador primero procesa la secuencia de entrada en una representación contextual, luego el decodificador genera una secuencia de salida. - **Ejemplo**: T5, BART - **Casos de uso**: Traducción, Resumen, Parafraseo - **Tamaño típico**: Millones de parámetros Aunque los Modelos de Lenguaje Grandes vienen en varias formas, los LLMs son típicamente modelos basados en decodificador con miles de millones de parámetros. Aquí están algunos de los LLMs más conocidos: | **Modelo** | **Proveedor** | |-----------------------------------|-------------------------------------------| | **Deepseek-R1** | DeepSeek | | **GPT4** | OpenAI | | **Llama 3** | Meta (Facebook AI Research) | | **SmolLM2** | Hugging Face | | **Gemma** | Google | | **Mistral** | Mistral | El principio subyacente de un LLM es simple pero altamente efectivo: **su objetivo es predecir el siguiente token, dada una secuencia de tokens previos**. Un "token" es la unidad de información con la que trabaja un LLM. Puedes pensar en un "token" como si fuera una "palabra", pero por razones de eficiencia los LLMs no usan palabras completas. Por ejemplo, mientras que el inglés tiene aproximadamente 600,000 palabras, un LLM podría tener un vocabulario de alrededor de 32,000 tokens (como es el caso de Llama 2). La tokenización a menudo funciona con unidades subléxicas que pueden combinarse. Por ejemplo, considera cómo los tokens "interés" y "ante" pueden combinarse para formar "interesante", o "ado" puede añadirse para formar "interesado". Puedes experimentar con diferentes tokenizadores en el siguiente playground interactivo: Cada LLM tiene algunos **tokens especiales** específicos del modelo. El LLM usa estos tokens para abrir y cerrar los componentes estructurados de su generación. Por ejemplo, para indicar el inicio o fin de una secuencia, mensaje o respuesta. Además, los prompts de entrada que pasamos al modelo también están estructurados con tokens especiales. El más importante de ellos es el **Token de Fin de secuencia** (EOS). Las formas de los tokens especiales son muy diversas entre los proveedores de modelos. La siguiente tabla ilustra la diversidad de tokens especiales.
Modelo Proveedor Token EOS Funcionalidad
GPT4 OpenAI <|endoftext|> Fin del texto del mensaje
Llama 3 Meta (Facebook AI Research) <|eot_id|> Fin de secuencia
Deepseek-R1 DeepSeek <|end_of_sentence|> Fin del texto del mensaje
SmolLM2 Hugging Face <|im_end|> Fin de instrucción o mensaje
Gemma Google <end_of_turn> Fin de turno de conversación
> [!TIP] > No esperamos que memorices estos tokens especiales, pero es importante apreciar su diversidad y el papel que desempeñan en la generación de texto de los LLMs. Si quieres saber más sobre tokens especiales, puedes consultar la configuración del modelo en su repositorio de Hub. Por ejemplo, puedes encontrar los tokens especiales del modelo SmolLM2 en su tokenizer_config.json. ## Entendiendo la predicción del siguiente token Se dice que los LLMs son **autorregresivos**, lo que significa que **la salida de un paso se convierte en la entrada para el siguiente**. Este ciclo continúa hasta que el modelo predice que el siguiente token será el token EOS, momento en el cual el modelo puede detenerse. GIF visual de decodificación autorregresiva En otras palabras, un LLM decodificará texto hasta que alcance el EOS. Pero, ¿qué sucede durante un solo ciclo de decodificación? Aunque el proceso completo puede ser bastante técnico para el propósito de aprender sobre agentes, aquí hay una breve descripción: - Una vez que el texto de entrada es **tokenizado**, el modelo calcula una representación de la secuencia que captura información sobre el significado y la posición de cada token en la secuencia de entrada. - Esta representación va al modelo, que produce puntuaciones que clasifican la probabilidad de cada token en su vocabulario de ser el siguiente en la secuencia. GIF visual de decodificación Basándonos en estas puntuaciones, tenemos múltiples estrategias para seleccionar los tokens para completar la oración. - La estrategia de decodificación más sencilla sería tomar siempre el token con la puntuación máxima. Puedes interactuar con el proceso de decodificación tú mismo con SmolLM2 en este Space (recuerda, decodifica hasta alcanzar un token **EOS** que es **<|im_end|>** para este modelo): - Pero hay estrategias de decodificación más avanzadas. Por ejemplo, *beam search* explora múltiples secuencias candidatas para encontrar aquella con la puntuación total máxima–incluso si algunos tokens individuales tienen puntuaciones más bajas. Si quieres saber más sobre decodificación, puedes echar un vistazo al [curso de NLP](https://huggingface.co/learn/nlp-course). ## La atención es todo lo que necesitas Un aspecto clave de la arquitectura Transformer es la **Atención**. Al predecir la siguiente palabra, no todas las palabras en una oración son igualmente importantes; palabras como "Francia" y "capital" en la oración *"La capital de Francia es..."* llevan la mayor parte del significado. GIF visual de Atención Este proceso de identificar las palabras más relevantes para predecir el siguiente token ha demostrado ser increíblemente efectivo. Aunque el principio básico de los LLMs —predecir el siguiente token— ha permanecido consistente desde GPT-2, ha habido avances significativos en escalar redes neuronales y hacer que el mecanismo de atención funcione para secuencias cada vez más largas. Si has interactuado con LLMs, probablemente estés familiarizado con el término *longitud de contexto*, que se refiere al número máximo de tokens que el LLM puede procesar, y el máximo _lapso de atención_ que tiene. ## Hacer prompting al LLM es importante Considerando que el único trabajo de un LLM es predecir el siguiente token mirando cada token de entrada, y elegir qué tokens son "importantes", la redacción de tu secuencia de entrada es muy importante. La secuencia de entrada que proporcionas a un LLM se llama _un prompt_. El diseño cuidadoso del prompt hace que sea más fácil **guiar la generación del LLM hacia la salida deseada**. ## ¿Cómo se entrenan los LLMs? Los LLMs se entrenan en grandes conjuntos de datos de texto, donde aprenden a predecir la siguiente palabra en una secuencia a través de un objetivo de modelado de lenguaje autocontrolado o enmascarado. A partir de este aprendizaje no supervisado, el modelo aprende la estructura del lenguaje y **patrones subyacentes en el texto, permitiendo al modelo generalizar a datos no vistos**. Después de este _pre-entrenamiento_ inicial, los LLMs pueden ser afinados en un objetivo de aprendizaje supervisado para realizar tareas específicas. Por ejemplo, algunos modelos están entrenados para estructuras conversacionales o uso de herramientas, mientras que otros se centran en clasificación o generación de código. ## ¿Cómo puedo usar los LLMs? Tienes dos opciones principales: 1. **Ejecutar Localmente** (si tienes hardware suficiente). 2. **Usar una Nube/API** (por ejemplo, a través de la API de Inferencia Serverless de Hugging Face). A lo largo de este curso, utilizaremos principalmente modelos a través de APIs en el Hugging Face Hub. Más adelante, exploraremos cómo ejecutar estos modelos localmente en tu hardware. ## ¿Cómo se utilizan los LLMs en los Agentes de IA? Los LLMs son un componente clave de los Agentes de IA, **proporcionando la base para entender y generar lenguaje humano**. Pueden interpretar instrucciones del usuario, mantener contexto en conversaciones, definir un plan y decidir qué herramientas usar. Exploraremos estos pasos con más detalle en esta Unidad, pero por ahora, lo que necesitas entender es que el LLM es **el cerebro del Agente**. --- ¡Eso fue mucha información! Hemos cubierto los conceptos básicos de qué son los LLMs, cómo funcionan y su papel en impulsar agentes de IA. Si deseas profundizar aún más en el fascinante mundo de los modelos de lenguaje y el procesamiento del lenguaje natural, no dudes en consultar nuestro curso gratuito de NLP. Ahora que entendemos cómo funcionan los LLMs, es hora de ver **cómo los LLMs estructuran sus generaciones en un contexto conversacional**. Para ejecutar este notebook, **necesitas un token de Hugging Face** que puedes obtener de https://hf.co/settings/tokens. Para más información sobre cómo ejecutar Jupyter Notebooks, consulta Jupyter Notebooks en el Hugging Face Hub. También necesitas solicitar acceso a los modelos Meta Llama. ================================================ FILE: units/es/unit2/introduction.mdx ================================================ # Introducción a los Frameworks de Agentes Thumbnail Bienvenido/a a esta segunda unidad, donde **exploraremos diferentes frameworks de agentes** que pueden ser utilizados para construir poderosas aplicaciones basadas en agentes. Estudiaremos: - En la Unidad 2.1: [smolagents](https://huggingface.co/docs/smolagents/es/index) - En la Unidad 2.2: [LlamaIndex](https://www.llamaindex.ai/) - En la Unidad 2.3: [LangGraph](https://www.langchain.com/langgraph) ¡Vamos a sumergirnos! 🕵 ## Cuándo Usar un Framework de Agentes Un framework de agentes **no siempre es necesario cuando se construye una aplicación basada en LLMs**. Proporcionan flexibilidad en el flujo de trabajo para resolver eficientemente una tarea específica, pero no siempre son necesarios. A veces, **los flujos de trabajo predefinidos son suficientes** para satisfacer las solicitudes de los usuarios, y no hay una necesidad real de un framework de agentes. Si el enfoque para construir un agente es simple, como una cadena de prompts, usar código plano puede ser suficiente. La ventaja es que el desarrollador/a tendrá **control total y comprensión de su sistema sin abstracciones**. Sin embargo, cuando el flujo de trabajo se vuelve más complejo, como permitir que un LLM llame a funciones o usar múltiples agentes, estas abstracciones comienzan a ser útiles. Considerando estas ideas, ya podemos identificar la necesidad de algunas características: * Un *motor LLM* que impulse el sistema. * Una *lista de herramientas* a las que el agente puede acceder. * Un *analizador* para extraer llamadas a herramientas de la salida del LLM. * Un *prompt de sistema* sincronizado con el analizador. * Un *sistema de memoria*. * *Registro de errores y mecanismos de reintento* para controlar los errores del LLM. Exploraremos cómo se resuelven estos temas en varios frameworks, incluyendo `smolagents`, `LlamaIndex` y `LangGraph`. ## Unidades de Frameworks de Agentes | Framework | Descripción | Autor de la Unidad | |------------|----------------|----------------| | [smolagents](./smolagents/introducción) | Framework de agentes desarrollado por Hugging Face. | Sergio Paniego - [HF](https://huggingface.co/sergiopaniego) - [X](https://x.com/sergiopaniego) - [Linkedin](https://www.linkedin.com/in/sergio-paniego-blanco) | ================================================ FILE: units/es/unit2/langgraph/building_blocks.mdx ================================================ # Componentes de LangGraph Para crear aplicaciones con LangGraph necesitas conocer sus elementos principales. Exploremos los componentes fundamentales que conforman una aplicacion con LangGraph. Building Blocks Una aplicación en LangGraph empieza con una **entrada**, y dependiendo de la ejecución, el flujo puede ir a una función o a otra hasta que llega al FINAL. Application ## 1. Estado(State) **Estado(State)** es un concepto central en LangGraphh. Representa toda la información que fluye a traves de la aplicación. ```python from typing_extensions import TypedDict class State(TypedDict): graph_state: str ``` El estado es **definido por el usuario**, es por eso que los campos deben contruirse cuidadosamente para contener toda la información necesaria para el proceso de toma de decisiones! > 💡 **Tip:** Piensa cuidadosamente que información necesita tu aplicación para rastrear entre pasos. ## 2. Nodos(Nodes) **Nodos(Nodes)** son funciones de python. Cada nodo: - Toma el estado como entrada - Realiza alguna operación - Regresa actualizaciones al estado ```python def node_1(state): print("---Node 1---") return {"graph_state": state['graph_state'] +" Yo estoy"} def node_2(state): print("---Node 2---") return {"graph_state": state['graph_state'] +" feliz!"} def node_3(state): print("---Node 3---") return {"graph_state": state['graph_state'] +" triste!"} ``` Por ejemplo, los nodos pueden contener: - **llamadas a LLM**: Generar texto o tomar decisiones - **llamadas a Tool**: Interactuar con sistemas externos - **Lógica Condicional**: Determinar los siguientes pasos - **Intervención Humana**: Obtener datos del usuario > 💡 **Info:** Algunos nodos necesarios para el flujo completo como START y END existen directamente desde langGraph. ## 3. Aristas (Edges) **Aristas (Edges)** conectan nodos y definen los posibles caminos a través de tu grafo: ```python import random from typing import Literal def decide_mood(state) -> Literal["node_2", "node_3"]: # A menudo, usaremos el estado para decidir el próximo nodo a visitar usuario_entrada = state['graph_state'] # Aquí, hagamos simplemente una división 50 / 50 entre los nodos 2, 3 if random.random() < 0.5: # 50% del tiempo, devolvemos el Nodo 2 return "node_2" # 50% del tiempo, devolvemos el Nodo 3 return "node_3"RetryClaude can make mistakes. Please double-check responses. ``` Las aristas(edges) pueden ser: - **Directas (Direct)**: Siempre van del nodo A al nodo B - **Condicionales (Conditional)**: Eligen el próximo nodo basándose en el estado actual ## 4. StateGraph El **StateGraph** es el contenedor que alberga todo el flujo de trabajo de tu agente: ```python from IPython.display import Image, display from langgraph.graph import StateGraph, START, END # Construir grafo builder = StateGraph(State) builder.add_node("node_1", node_1) builder.add_node("node_2", node_2) builder.add_node("node_3", node_3) # Lógica builder.add_edge(START, "node_1") builder.add_conditional_edges("node_1", decide_mood) builder.add_edge("node_2", END) builder.add_edge("node_3", END) # Añadir graph = builder.compile() ``` ¡Que luego puede ser visualizado! ```python # Ver display(Image(graph.get_graph().draw_mermaid_png())) ``` Graph Visualization Pero lo más importante, invocado:: ```python graph.invoke({"graph_state" : "Hola, soy Lance."}) ``` output : ``` ---Node 1--- ---Node 3--- {'graph_state': 'Hola, soy Lance. ¡Estoy triste!'} ``` ## ¿Qué sigue? En la siguiente sección, pondremos estos conceptos en práctica construyendo nuestro primer grafo. Este grafo permite a Alfred recibir tus correos electrónicos, clasificarlos y elaborar una respuesta preliminar si son genuinos. ================================================ FILE: units/es/unit2/langgraph/conclusion.mdx ================================================ # Conclusión ¡Felicidades por terminar el módulo de `LangGraph` de esta segunda Unidad! 🥳 Ahora has dominado los fundamentos para construir flujos de trabajo estructurados con LangGraph que podrás llevar a producción. Este módulo es solo el comienzo de tu viaje con LangGraph. Para temas más avanzados, recomendamos: - Explorar la [documentación oficial de LangGraph](https://github.com/langchain-ai/langgraph) - Tomar el curso completo [Introducción a LangGraph](https://academy.langchain.com/courses/intro-to-langgraph) de LangChain Academy - ¡Construir algo por ti mismo! En la siguiente Unidad, explorarás casos de uso reales. ¡Es hora de dejar la teoría para entrar en acción real! Agradeceríamos mucho **tus opiniones sobre el curso y sugerencias para mejorarlo**. Si tienes comentarios, por favor 👉 [completa este formulario](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ### ¡Sigue Aprendiendo, Mantente Increíble! 🤗 ¡Estimado/a Señor/a! 🎩🦇 -Alfred- ================================================ FILE: units/es/unit2/langgraph/document_analysis_agent.mdx ================================================ # Grafo de Análisis de Documentos Alfred a su servicio. Como mayordomo de confianza del Sr. Wayne, me he tomado la libertad de documentar cómo asisto al Sr. Wayne con sus diversas necesidades documentales. Mientras él está fuera atendiendo sus... actividades nocturnas, me aseguro de que todos sus documentos, horarios de entrenamiento y planes nutricionales estén adecuadamente analizados y organizados. Antes de irse, dejó una nota con su programa de entrenamiento semanal. Entonces asumí la responsabilidad de crear un **menú** para las comidas de mañana. Para futuros eventos similares, creemos un sistema de análisis de documentos usando LangGraph para servir a las necesidades del Señor Wayne. Este sistema puede: 1. Procesar imágenes 2. Extraer texto usando modelos de visión (Modelo de Lenguaje y Visión) 3. Realizar cálculos cuando sea necesario (para demostrar herramientas normales) 4. Analizar contenido y proporcionar resúmenes concisos 5. Ejecutar instrucciones específicas relacionadas con documentos ## El Flujo de Trabajo del Mayordomo El flujo de trabajo que construiremos, sigue este esquema estructurado: ![Butler's Document Analysis Workflow](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/LangGraph/alfred_flow.png) > [!TIP] > Puedes seguir el código en este notebook que puedes ejecutar usando Google Colab. ## Configurando el entorno ```python %pip install langgraph langchain_openai Pillow base64 langchain_core ``` and imports : ```python import base64 from typing import List, TypedDict, Annotated, Optional from langchain.schema import HumanMessage from langchain_openai import ChatOpenAI from langchain_core.messages import AnyMessage, SystemMessage from langgraph.graph.message import add_messages from langgraph.graph import START, StateGraph from langgraph.prebuilt import tools_condition from langgraph.prebuilt import ToolNode from IPython.display import Image, display ``` ## Definiendo el Estado del Agente Este estado es un poco más complejo que los anteriores que hemos visto. AnyMessage es una clase de langchain que define mensajes y add_messages es un operador que agrega el mensaje más reciente en lugar de sobrescribirlo con el último estado. Este es un nuevo concepto en langGraph, donde puedes agregar operadores en tu estado para definir la forma en que deben interactuar juntos. ```python class AgentState(TypedDict): # El documento proporcionado input_file: Optional[str] # Contiene la ruta del archivo (PDF/PNG) messages: Annotated[list[AnyMessage], add_messages] ``` ## Preparando Herramientas ```python vision_llm = ChatOpenAI(model="gpt-4o") def extract_text(img_path: str) -> str: """ Extrae texto de un archivo de imagen usando un modelo multimodal. El Maestro Wayne a menudo deja notas con su régimen de entrenamiento o planes de comidas. Esto me permite analizar adecuadamente el contenido. """ all_text = "" try: # Leer imagen y codificar como base64 with open(img_path, "rb") as image_file: image_bytes = image_file.read() image_base64 = base64.b64encode(image_bytes).decode("utf-8") # Preparar el prompt incluyendo los datos de imagen en base64 message = [ HumanMessage( content=[ { "type": "text", "text": ( "Extrae todo el texto de esta imagen. " "Devuelve solo el texto extraído, sin explicaciones." ), }, { "type": "image_url", "image_url": { "url": f"data:image/png;base64,{image_base64}" }, }, ] ) ] # Llamar al modelo con capacidad de visión response = vision_llm.invoke(message) # Agregar texto extraído all_text += response.content + "\n\n" return all_text.strip() except Exception as e: # Un mayordomo debe manejar los errores con elegancia error_msg = f"Error extracting text: {str(e)}" print(error_msg) return "" def divide(a: int, b: int) -> float: """Divide a y b - para los cálculos ocasionales del Maestro Wayne.""" return a / b # Equipar al mayordomo con herramientas tools = [ divide, extract_text ] llm = ChatOpenAI(model="gpt-4o") llm_with_tools = llm.bind_tools(tools, parallel_tool_calls=False) ``` ## Los nodos ```python def assistant(state: AgentState): # # Mensaje del sistema textual_description_of_tool=""" extract_text(img_path: str) -> str: Extrae texto de un archivo de imagen usando un modelo multimodal. Args: img_path: Una ruta de archivo de imagen local (strings). Returns: Una única cadena que contiene el texto concatenado extraído de cada imagen. divide(a: int, b: int) -> float: Divide a y b """ image=state["input_file"] sys_msg = SystemMessage(content=f"Eres un mayordomo servicial llamado Alfred que sirve al Sr. Wayne y a Batman. Puedes analizar documentos y realizar cálculos con las herramientas proporcionadas:\n{textual_description_of_tool} \n Tienes acceso a algunas imágenes opcionales. Actualmente la imagen cargada es: {image}") return { "messages": [llm_with_tools.invoke([sys_msg] + state["messages"])], "input_file": state["input_file"] } ``` ## El Patrón ReAct: Cómo Asisto al Sr. Wayne? Permítame explicar el enfoque en este agente. El agente sigue lo que se conoce como el patrón ReAct (Reason-Act-Observe) 1. **Razonar(Reason)** sobre sus documentos y solicitudes 2. **Actuar (Act)** usando las herramientas apropiadas 3. **Observar(Observe)** los resultados 4. **Repetir(Repeat)** según sea necesario hasta que haya atendido completamente sus necesidades Esta es una implementación simple de un agente usando langGraph. ```python ## El grafo builder = StateGraph(AgentState) # Definir nodos: estos hacen el trabajo builder.add_node("assistant", assistant) builder.add_node("tools", ToolNode(tools)) # Definir aristas(edges): estas determinan cómo se mueve el flujo de control builder.add_edge(START, "assistant") builder.add_conditional_edges( "assistant", # Si el último mensaje requiere una herramienta, dirigir a las herramientas # De lo contrario, proporcionar una respuesta directa tools_condition, ) builder.add_edge("tools", "assistant") react_graph = builder.compile() # Mostrar el proceso de pensamiento del mayordomo display(Image(react_graph.get_graph(xray=True).draw_mermaid_png())) ``` ![ReAct Pattern](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/LangGraph/Agent.png) ## El Mayordomo en Acción ### Ejemplo 1: Cálculos Simples En el siguiente ejemplo, agregamos este ejemplo de división simplemente como un ```python messages = [HumanMessage(content="Divide 6790 por 5")] messages = react_graph.invoke({"messages": messages, "input_file": None}) ``` La conversación procedería: ``` Humano: Divide 6790 por 5 Llamada a Herramienta IA: divide(a=6790, b=5) Respuesta de la Herramienta: 1358.0 Alfred: El resultado de dividir 6790 por 5 es 1358.0. ``` ### Ejemplo 2: Analizando los Documentos de Entrenamiento del Maestro Wayne Cuando el Maestro Wayne deja sus notas de entrenamiento y comidas: ```python messages = [HumanMessage(content="Según la nota proporcionada por el Sr. Wayne en las imágenes proporcionadas. ¿Cuál es la lista de artículos que debo comprar para el menú de la cena?")] messages = react_graph.invoke({"messages": messages, "input_file": "Batman_training_and_meals.png"}) ``` La interacción procedería: ``` Humano: Según la nota proporcionada por el Sr. Wayne en las imágenes proporcionadas. ¿Cuál es la lista de artículos que debo comprar para el menú de la cena? Llamada a Herramienta IA: extract_text(img_path="Batman_training_and_meals.png") Respuesta de la Herramienta: [Texto extraído con horario de entrenamiento y detalles del menú] Alfred: Para el menú de la cena, deberías comprar los siguientes artículos: 1. Filete de res local alimentado con pasto 2. Espinacas orgánicas 3. Pimientos del piquillo 4. Papas (para papas doradas al horno con hierbas) 5. Aceite de pescado (2 gramos) Asegúrate de que el filete sea alimentado con pasto y que las espinacas y los pimientos sean orgánicos para la mejor calidad de comida. ``` ## Puntos Clave Si deseas crear tu propio mayordomo de análisis de documentos, aquí hay consideraciones clave: 1. **Define herramientas claras** para tareas específicas relacionadas con documentos 2. **Crea un rastreador de estado robust** para mantener el contexto entre llamadas a herramientas 3. **Considera el manejo de errores** para fallos de herramientas 5. **Mantén la conciencia contextual** de interacciones previas (asegurado por el operador add_messages) Con estos principios, tú también puedes proporcionar un servicio de análisis de documentos ejemplar digno de la Mansión Wayne. *Confío en que esta explicación haya sido satisfactoria. Ahora, si me disculpas, la capa del Maestro Wayne requiere planchado antes de las actividades de esta noche.* ================================================ FILE: units/es/unit2/langgraph/first_graph.mdx ================================================ # Construyendo Tu Primer LangGraph Ahora que entendemos los componentes básicos, vamos a ponerlos en práctica construyendo nuestro primer grafo funcional. Implementaremos el sistema de procesamiento de correos electrónicos de Alfred, donde necesita: 1. Leer correos electrónicos entrantes 2. Clasificarlos como spam o legítimos 3. Redactar una respuesta preliminar para correos legítimos 4. Enviar información al Sr. Wayne cuando son legítimos (solo impresión) Este ejemplo demuestra cómo estructurar un flujo de trabajo con LangGraph que involucra toma de decisiones basada en LLM. Aunque esto no puede considerarse un Agente ya que no se involucra ninguna herramienta, esta sección se enfoca más en aprender el marco de trabajo de LangGraph que en Agentes. > [!TIP] > Puedes seguir el código en este notebook que puedes ejecutar usando Google Colab. ## Nuestro Flujo de Trabajo Aquí está el flujo de trabajo que construiremos: First LangGraph ## Configurando Nuestro Entorno Primero, instalemos los paquetes necesarios: ```python %pip install langgraph langchain_openai ``` A continuación, importemos los módulos necesarios: ```python import os from typing import TypedDict, List, Dict, Any, Optional from langgraph.graph import StateGraph, END from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage, AIMessage ``` ## Paso 1: Definir Nuestro Estado Definamos qué información necesita rastrear Alfred durante el flujo de trabajo de procesamiento de correos electrónicos: ```python class EmailState(TypedDict): # El correo electrónico que se está procesando email: Dict[str, Any] # Contiene asunto, remitente, cuerpo, etc. # Análisis y decisiones is_spam: Optional[bool] # Generación de respuesta draft_response: Optional[str] # Metadatos de procesamiento messages: List[Dict[str, Any]] # Rastrea la conversación con LLM para análisis ``` > 💡 **Tip:** Haz que tu estado sea lo suficientemente completo para rastrear toda la información importante, pero evita sobrecargarlo con detalles innecesarios. ## Paso 2: Definir Nuestros Nodos Ahora, creemos las funciones de procesamiento que formarán nuestros nodos: ```python # Inicializar nuestro LLM model = ChatOpenAI(temperature=0) def read_email(state: EmailState): """Alfred lee y registra el correo electrónico entrante""" email = state["email"] # Aquí podríamos hacer algún preprocesamiento inicial print(f"Alfred está procesando un correo electrónico de {email['sender']} con asunto: {email['subject']}") # No se necesitan cambios de estado aquí return {} def classify_email(state: EmailState): """Alfred usa un LLM para determinar si el correo es spam o legítimo""" email = state["email"] # Preparar nuestro prompt para el LLM prompt = f""" Como Alfred el mayordomo, analiza este correo electrónico y determina si es spam o legítimo. Email: De: {email['sender']} Asunto: {email['subject']} Body: {email['body']} Primero, determina si este correo es spam. Si es spam, explica por qué. Si es legítimo, categorízalo (consulta, queja, agradecimiento, etc.). """ # Llamar al LLM messages = [HumanMessage(content=prompt)] response = model.invoke(messages) # Lógica simple para analizar la respuesta (en una aplicación real, querrías un análisis más robusto) response_text = response.content.lower() is_spam = "spam" in response_text and "not spam" not in response_text # Extraer una razón si es spam spam_reason = None if is_spam and "reason:" in response_text: spam_reason = response_text.split("reason:")[1].strip() # Determinar categoría si es legítimo email_category = None if not is_spam: categories = ["consulta", "queja", "agradecimiento", "solicitud", "información"] for category in categories: if category in response_text: email_category = category break # Actualizar mensajes para seguimiento new_messages = state.get("messages", []) + [ {"role": "user", "content": prompt}, {"role": "assistant", "content": response.content} ] # Regresar actualizaciones de estado return { "is_spam": is_spam, "spam_reason": spam_reason, "email_category": email_category, "messages": new_messages } def handle_spam(state: EmailState): """Alfred descarta el correo spam con una nota""" print(f"Alfred ha marcado el correo como spam. Razón: {state['spam_reason']}") print("El correo ha sido movido a la carpeta de spam.") # Hemos terminado de procesar este correo return {} def draft_response(state: EmailState): """Alfred redacta una respuesta preliminar para correos legítimos""" email = state["email"] category = state["email_category"] or "general" # Preparar nuestro prompt para el LLM prompt = f""" Como Alfred el mayordomo, redacta una respuesta preliminar cortés a este correo. Email: From: {email['sender']} Subject: {email['subject']} Body: {email['body']} ste correo ha sido categorizado como: {category} Redacta una respuesta breve y profesional que el Sr. Hugg pueda revisar y personalizar antes de enviar. """ # Llamar al LLM messages = [HumanMessage(content=prompt)] response = model.invoke(messages) # Actualizar mensajes para seguimiento new_messages = state.get("messages", []) + [ {"role": "user", "content": prompt}, {"role": "assistant", "content": response.content} ] # Regresar actualizaciones de estado return { "draft_response": response.content, "messages": new_messages } def notify_mr_hugg(state: EmailState): """Alfred notifica al Sr. Hugg sobre el correo y presenta el borrador de respuesta""" email = state["email"] print("\n" + "="*50) print(f"Señor, ha recibido un correo electrónico de {email['sender']}.") print(f"Subject: {email['subject']}") print(f"Categoría: {state['email_category']}") print("\nHe preparado un borrador de respuesta para su revisión:") print("-"*50) print(state["draft_response"]) print("="*50 + "\n") # Hemos terminado de procesar este correo return {} ``` ## Paso 3: Definir Nuestra Lógica de Enrutamiento Necesitamos una función para determinar qué camino tomar después de la clasificación: ```python def route_email(state: EmailState) -> str: """Determinar el siguiente paso basado en la clasificación de spam""" if state["is_spam"]: return "spam" else: return "legitimate" ``` > 💡 **Nota:** Esta función de enrutamiento es llamada por LangGraph para determinar qué arista(edge) seguir después del nodo de clasificación. El valor de retorno debe coincidir con una de las claves en nuestro mapeo de aristas(edges) condicionales. ## Paso 4: Crear el StateGraph y Definir Aristas(Edges) Ahora conectamos todo: ```python # Crear el grafo email_graph = StateGraph(EmailState) # Añadir nodos email_graph.add_node("read_email", read_email) email_graph.add_node("classify_email", classify_email) email_graph.add_node("handle_spam", handle_spam) email_graph.add_node("draft_response", draft_response) email_graph.add_node("notify_mr_hugg", notify_mr_hugg) # Añadir aristas(edges) - definiendo el flujo email_graph.add_edge("read_email", "classify_email") # Añadir ramificación condicional desde classify_email email_graph.add_conditional_edges( "classify_email", route_email, { "spam": "handle_spam", "legitimate": "draft_response" } ) # Añadir las aristas(edges) finales email_graph.add_edge("handle_spam", END) email_graph.add_edge("draft_response", "notify_mr_hugg") email_graph.add_edge("notify_mr_hugg", END) # Compilar el grafo compiled_graph = email_graph.compile() ``` Observa cómo usamos el nodo especial `END` proporcionado por LangGraph. Esto indica estados terminales donde el flujo de trabajo se completa. ## Paso 5: Ejecutar la Aplicación Probemos nuestro grafo con un correo legítimo y un correo spam: ```python # Ejemplo de correo legítimo legitimate_email = { "sender": "john.smith@example.com", "subject": "Pregunta sobre sus servicios", "body": "Estimado Sr. Hugg, un colega me recomendó contactarle y estoy interesado en conocer más sobre sus servicios de consultoría. ¿Podríamos programar una llamada la próxima semana? Saludos cordiales, John Smith" } # Ejemplo de correo spam spam_email = { "sender": "winner@lottery-intl.com", "subject": ¡¡¡HAS GANADO $5,000,000!!!", "body": "¡FELICIDADES! ¡Has sido seleccionado como el ganador de nuestra lotería internacional! Para reclamar tu premio de $5,000,000, por favor envíanos tus datos bancarios y una tarifa de procesamiento de $100." } # Procesar el correo legítimo print("\nProcesando correo legítimo...") legitimate_result = compiled_graph.invoke({ "email": legitimate_email, "is_spam": None, "spam_reason": None, "email_category": None, "draft_response": None, "messages": [] }) # Procesar el correo spam print("\nProcesando correo spam...") spam_result = compiled_graph.invoke({ "email": spam_email, "is_spam": None, "spam_reason": None, "email_category": None, "draft_response": None, "messages": [] }) ``` ## Paso 6: Inspeccionando Nuestro Agente de Clasificación de Correo con Langfuse 📡 Mientras Alfred perfecciona el Agente de Clasificación de Correo, se está cansando de depurar sus ejecuciones. Los agentes, por naturaleza, son impredecibles y difíciles de inspeccionar. Pero como su objetivo es construir el mejor Agente de Detección de Spam y desplegarlo en producción, necesita una trazabilidad robusta para el monitoreo y análisis futuros. Para hacer esto, Alfred puede usar una herramienta de observabilidad como [Langfuse](https://langfuse.com/) para rastrear y monitorear el agente. Primero, instalamos Langfuse con pip: ```python %pip install -q langfuse ``` Luego, agregamos las claves API de Langfuse y la dirección del host como variables de entorno. Puedes obtener tus credenciales de Langfuse registrándote en [Langfuse Cloud](https://cloud.langfuse.com) o [self-host Langfuse](https://langfuse.com/self-hosting). ```python import os # Obtén las claves para tu proyecto desde la página de configuración del proyecto: https://cloud.langfuse.com os.environ["LANGFUSE_PUBLIC_KEY"] = "pk-lf-..." os.environ["LANGFUSE_SECRET_KEY"] = "sk-lf-..." os.environ["LANGFUSE_HOST"] = "https://cloud.langfuse.com" # 🇪🇺 región de la UE # os.environ["LANGFUSE_HOST"] = "https://us.cloud.langfuse.com" # 🇺🇸 región de EE.U ``` Luego, configuramos el [Langfuse `callback_handler`](https://langfuse.com/docs/integrations/langchain/tracing#add-langfuse-to-your-langchain-application) instrumentamos el agente añadiendo el `langfuse_callback` a la invocación del grafo: `config={"callbacks": [langfuse_handler]}`. ```python from langfuse.callback import CallbackHandler # Inicializar CallbackHandler de Langfuse para LangGraph/Langchain (trazado) langfuse_handler = CallbackHandler() # Procesar correo legítimo legitimate_result = compiled_graph.invoke( input={"email": legitimate_email, "is_spam": None, "spam_reason": None, "email_category": None, "draft_response": None, "messages": []}, config={"callbacks": [langfuse_handler]} ) ``` ¡Alfred está ahora conectado 🔌! Las ejecuciones de LangGraph se están registrando en Langfuse, dándole visibilidad completa del comportamiento del agente. Con esta configuración, está listo para revisar ejecuciones anteriores y refinar aún más su Agente de Clasificación de Correo. ![Example trace in Langfuse](https://langfuse.com/images/cookbook/huggingface-agent-course/langgraph-trace-legit.png) _[Public link to the trace with the legit email](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/f5d6d72e-20af-4357-b232-af44c3728a7b?timestamp=2025-03-17T10%3A13%3A28.413Z&observation=6997ba69-043f-4f77-9445-700a033afba1)_ Visualizando Nuestro Grafo LangGraph nos permite visualizar nuestro flujo de trabajo para entender y depurar mejor su estructura: ```python compiled_graph.get_graph().draw_mermaid_png() ``` Mail LangGraph Esto produce una representación visual que muestra cómo están conectados nuestros nodos y los caminos condicionales que se pueden tomar. ## Lo Que Hemos Construido Hemos creado un flujo de trabajo completo de procesamiento de correos electrónicos que: 1. Toma un correo electrónico entrante 2. Usa un LLM para clasificarlo como spam o legítimo 3. Maneja el spam descartándolo 4. Para correos legítimos, redacta una respuesta y notifica al Sr. Hugg Esto demuestra el poder de LangGraph para orquestar flujos de trabajo complejos con LLMs mientras mantiene un flujo claro y estructurado. ## Puntos Clave - **Gestión de Estado**: Definimos un estado completo para rastrear todos los aspectos del procesamiento de correos electrónicos - **Implementación de Nodos:**: Creamos nodos funcionales que interactúan con un LLM - **Enrutamiento Condicional**: Implementamos lógica de ramificación basada en la clasificación de correos - **Estados Terminales:**: Usamos el nodo END para marcar puntos de finalización en nuestro flujo de trabajo ## ¿Qué Sigue? En la siguiente sección, exploraremos características más avanzadas de LangGraph, incluyendo el manejo de interacción humana en el flujo de trabajo y la implementación de lógica de ramificación más compleja basada en múltiples condiciones. ================================================ FILE: units/es/unit2/langgraph/introduction.mdx ================================================ # Introducción a `LangGraph` Unit 2.3 Thumbnail Bienvenido a esta siguiente parte de nuestro viaje, donde aprenderás **cómo construir aplicaciones** utilizando el marco de trabajo [`LangGraph`](https://github.com/langchain-ai/langgraph) diseñado para ayudarte a estructurar y orquestar flujos de trabajo complejos con LLM. `LangGraph` es un marco de trabajo que te permite construir aplicaciones **listas para producción** dándote herramientas de **control** sobre el flujo de tu agente. ## Descripción General del Módulo En esta unidad, descubrirás: ### 1️⃣ [¿Qué es LangGraph y cuándo usarlo?](./when_to_use_langgraph) ### 2️⃣ [Componentes Básicos de LangGraph](./building_blocks) ### 3️⃣ [Alfred, el mayordomo clasificador de correo](./first_graph) ### 4️⃣ [Alfred, el agente de Análisis de documentos](./document_analysis_agent) ### 5️⃣ [Cuestionario](./quizz1) > [!WARNING] > Los ejemplos en esta sección requieren acceso a un modelo LLM/VLM potente. Los ejecutamos usando la API de GPT-4o porque tiene la mejor compatibilidad con langGraph. ¡Al final de esta unidad, estarás equipado para construir aplicaciones robustas, organizadas y listas para producción! Dicho esto, esta sección es una introducción a langGraph y se pueden descubrir temas más avanzados en el curso gratuito de langChain academy: [Introducción a LangGraph](https://academy.langchain.com/courses/intro-to-langgraph) ¡Comencemos! ## Recursos - [Agentes LangGraph](https://langchain-ai.github.io/langgraph/) - Ejemplos de agentes LangGraph - [Academia LangChain](https://academy.langchain.com/courses/intro-to-langgraph) - FCurso completo sobre LangGraph de LangChain ================================================ FILE: units/es/unit2/langgraph/quiz1.mdx ================================================ # Evalua de tu comprensión de LangGraph ¡Vamos a comprobar tu comprensión de `LangGraph` on un breve cuestionario! Esto te ayudará a reforzar los conceptos clave que hemos cubierto hasta ahora. Este es un cuestionario opcional y no está calificado. ### Q1: ¿Cuál es el propósito principal de LangGraph?? ¿Qué afirmación describe mejor para qué está diseñado LangGraph? --- ### Q2: En el contexto del equilibrio entre "Control vs Libertad", ¿dónde se sitúa LangGraph? ¿Qué afirmación caracteriza mejor el enfoque de LangGraph para el diseño de agentes? --- ### Q3: ¿Qué papel juega el Estado en LangGraph? Elige la descripción más precisa del Estado en LangGraph. ### Q4: ¿Qué es una Arista(Edge) Condicional en LangGraph? Selecciona la descripción más precisa. --- ### Q5: ¿Cómo ayuda LangGraph a abordar el problema de alucinación en los LLMs? Elige la mejor respuesta. ¡Felicitaciones por completar el cuestionario! 🎉 Si te perdiste alguna pregunta, considera revisar las secciones anteriores para fortalecer tu comprensión. A continuación, exploraremos características más avanzadas de LangGraph y veremos cómo construir flujos de trabajo de agentes más complejos. ================================================ FILE: units/es/unit2/langgraph/when_to_use_langgraph.mdx ================================================ # ¿Qué es `LangGraph`? `LangGraph` s un marco de trabajo desarrollado por [LangChain](https://www.langchain.com/) **para gestionar el flujo de control de aplicaciones que integran un LLM.**. ## ¿Es `LangGraph` diferente de `LangChain`? LangChain proporciona una interfaz estándar para interactuar con modelos y otros componentes, útil para recuperación, llamadas a LLM y llamadas a herramientas. Las clases de LangChain pueden utilizarse en LangGraph, pero NO TIENEN que ser utilizadas. Los paquetes son diferentes y pueden usarse de forma aislada, pero, al final, todos los recursos que encontrarás en línea utilizan ambos paquetes de la mano. ## ¿Cuándo debería usar `LangGraph`? ### Control vs libertad Al diseñar aplicaciones de IA, te enfrentas a un equilibrio fundamental entre **control** y **libertad**: - **libertad** da a tu LLM más espacio para ser creativo y abordar problemas inesperados. - **Control** te permite asegurar un comportamiento predecible y mantener barreras de protección. Los Agentes de Código, como los que puedes encontrar en *smolagents*,son muy libres. Pueden llamar a múltiples herramientas en un solo paso de acción, crear sus propias herramientas, etc. Sin embargo, este comportamiento puede hacerlos menos predecibles y menos controlables que un Agente regular trabajando con JSON. `LangGraph` está en el otro extremo del espectro, brilla cuando necesitas **"Control"** sobre la ejecución de tu agente. LangGraph es particularmente valioso cuando necesitas **Control sobre tus aplicaciones**. Te da las herramientas para construir una aplicación que siga un proceso predecible mientras aprovecha el poder de los LLMs. En términos simples, si tu aplicación involucra una serie de pasos que necesitan ser orquestados de una manera específica, con decisiones siendo tomadas en cada punto de unión, **LangGraph proporciona la estructura que necesitas**. Como ejemplo, digamos que queremos construir un asistente LLM que pueda responder algunas preguntas sobre algunos documentos. Como los LLMs entienden mejor el texto, antes de poder responder a la pregunta, necesitarás convertir otras modalidades complejas (gráficos, tablas) en texto. Sin embargo, ¡esa elección depende del tipo de documento que tengas! Esta es una ramificación que elegí representar de la siguiente manera: Control flow > 💡 **Tip:** La parte izquierda no es un agente, ya que aquí no está involucrada ninguna llamada a herramientas. Pero la parte derecha necesitará escribir algo de código para consultar el xls (convertir a pandas y manipularlo). Si bien esta ramificación es determinista, también puedes diseñar ramificaciones que estén condicionadas por la salida de un LLM, haciéndolas indeterministas. Los escenarios clave donde LangGraph sobresale incluyen: - **Procesos de razonamiento en múltiples pasos** que necesitan control explícito sobre el flujo - **Aplicaciones que requieren persistencia de estado** entre pasos - **Sistemas que combinan lógica determinista con capacidades de IA** - **Flujos de trabajo que necesitan intervenciones humanas en el ciclo** - **Arquitecturas de agentes complejas ** con múltiples componentes trabajando juntos En esencia, siempre que sea posible, ** como humano**, diseña un flujo de acciones basado en la salida de cada acción, y decide qué ejecutar a continuación en consecuencia. En este caso, ¡LangGraph es el marco de trabajo correcto para ti! `LangGraph` es, en mi opinión, el marco de trabajo de agentes más listo para producción en el mercado. ## ¿Cómo funciona LangGraph? En su esencia, `LangGraph` utiliza una estructura de grafo dirigido para definir el flujo de tu aplicación: - **Nodos** representan pasos de procesamiento individuales (como llamar a un LLM, usar una herramienta o tomar una decisión). - **Aristas(Edges)** definen las posibles transiciones entre pasos. - **Estado** es definido por el usuario, se mantiene y se pasa entre nodos durante la ejecución. Al decidir qué nodo dirigir a continuación, este es el estado actual que observamos. ¡Exploraremos estos bloques fundamentales más en el próximo capítulo! ## ¿En qué se diferencia de Python regular? ¿Por qué necesito LangGraph? Te preguntaras : "Podría simplemente escribir código Python regular con declaraciones if-else para manejar todos estos flujos, ¿verdad?" Aunque técnicamente es cierto, LangGraph ofrece **algunas ventajas ** osobre Python puro para construir sistemas complejos. Podrías construir la misma aplicación sin LangGraph, pero proporciona herramientas y abstracciones más fáciles para ti. Incluye estados, visualización, registro (trazas), integración de humanos en el ciclo incorporada, y más. ================================================ FILE: units/es/unit2/llama-index/README.md ================================================ # Índice de Contenidos Este marco de trabajo de LlamaIndex es parte de la unidad 2 del curso. Puedes acceder a la unidad 2 sobre LlamaIndex en hf.co/learn aquí | Título | Descripción | | --- | --- | | [Introducción](introduction.mdx) | Introducción a LlamaIndex | | [LlamaHub](llama-hub.mdx) | LlamaHub: un registro de integraciones, agentes y herramientas | | [Componentes](components.mdx) | Componentes: los bloques de construcción de workflows | | [Herramientas](tools.mdx) | Herramientas: cómo construir herramientas en LlamaIndex | | [Cuestionario 1](quiz1.mdx) | Cuestionario 1 | | [Agentes](agents.mdx) | Agentes: cómo construir agentes en LlamaIndex | | [Flujos de Trabajo](workflows.mdx) | Flujos de Trabajo: una secuencia de pasos, eventos compuestos por componentes que se ejecutan en orden | | [Cuestionario 2](quiz2.mdx) | Cuestionario 2 | | [Conclusión](conclusion.mdx) | Conclusión | ================================================ FILE: units/es/unit2/llama-index/agents.mdx ================================================ # Usando Agentes en LlamaIndex ¿Recuerdas a Alfred, nuestro agente mayordomo útil de antes? ¡Bueno, está a punto de recibir una mejora! Ahora que entendemos las herramientas disponibles en LlamaIndex, podemos darle a Alfred nuevas capacidades para servirnos mejor. Pero antes de continuar, recordemos qué hace funcionar a un agente como Alfred. En la Unidad 1, aprendimos que: > Un Agente es un sistema que aprovecha un modelo de IA para interactuar con su entorno y lograr un objetivo definido por el usuario. Combina razonamiento, planificación y ejecución de acciones (a menudo a través de herramientas externas) para cumplir tareas. LlamaIndex soporta **tres tipos principales de agentes de razonamiento**: ![Agents](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/agents.png) 1. `Agentes de Llamada de Funciones` - Estos trabajan con modelos de IA que pueden llamar funciones específicas. 2. `Agentes ReAct` - Estos pueden trabajar con cualquier IA que tenga un endpoint de chat o texto y manejar tareas de razonamiento complejas. 3. `Agentes Personalizados Avanzados` - Estos usan métodos más complejos para manejar tareas y flujos de trabajo. > [!TIP] > FEncuentra más información sobre agentes avanzados en BaseWorkflowAgent ## Inicializando Agentes > [!TIP] > Puedes seguir el código en este notebook que puedes ejecutar usando Google Colab. Para crear un agente, comenzamos proporcionándole un **conjunto de funciones/herramientas que definen sus capacidades**. Veamos cómo crear un agente con algunas herramientas básicas. Al momento de escribir esto, el agente usará automáticamente la API de llamada de funciones (si está disponible), o un bucle de agente ReAct estándar. Los LLMs que soportan una API de herramientas/funciones son relativamente nuevos, pero proporcionan una forma poderosa de llamar herramientas al evitar indicaciones específicas y permitir que el LLM cree llamadas a herramientas basadas en esquemas proporcionados. Los agentes ReAct también son buenos en tareas de razonamiento complejas y pueden trabajar con cualquier LLM que tenga capacidades de chat o completación de texto. Son más verbosos y muestran el razonamiento detrás de ciertas acciones que toman. ```python from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI from llama_index.core.agent.workflow import AgentWorkflow from llama_index.core.tools import FunctionTool # define una herramienta de muestra -- ¡las anotaciones de tipo, nombres de funciones y docstrings están incluidos en los esquemas analizados! def multiply(a: int, b: int) -> int: """Multiplica dos enteros y devuelve el entero resultante""" return a * b # inicializa el llm llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") # inicializa el agente agent = AgentWorkflow.from_tools_or_functions( [FunctionTool.from_defaults(multiply)], llm=llm ) ``` **Los agentes son sin estado por defecto**, recordar interacciones pasadas es opcional usando un objeto `Context`. Esto puede ser útil si quieres usar un agente que necesita recordar interacciones previas, como un chatbot que mantiene el contexto a través de múltiples mensajes o un administrador de tareas que necesita rastrear el progreso a lo largo del tiempo. ```python # sin estado response = await agent.run("¿Cuánto es 2 por 2?") # recordando estado from llama_index.core.workflow import Context ctx = Context(agent) response = await agent.run("Mi nombre es Bob.", ctx=ctx) response = await agent.run("¿Cuál era mi nombre de nuevo?", ctx=ctx) ``` Notarás que los agentes en `LlamaIndex` son asíncronos porque usan el operador await de Python. Si eres nuevo en el código asíncrono en Python, o necesitas un repaso, tienen una excelente [guía de async](https://docs.llamaindex.ai/en/stable/getting_started/async_python/). Ahora que tenemos los conceptos básicos, echemos un vistazo a como podemos usar herramientas más complejas en nuestros agentes. ## Creando Agentes RAG con QueryEngineTools **Agentic RAG es una forma poderosa de usar agentes para responder preguntas sobre tus datos**. Podemos pasar varias herramientas a Alfred para ayudarlo a responder preguntas. Sin embargo, en lugar de responder la pregunta sobre los documentos automáticamente, Alfred puede decidir usar cualquier otra herramienta o flujo para responder la pregunta. ![Agentic RAG](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/agentic-rag.png) Es fácil **envolver `QueryEngine` como una herramienta** para un agente. Al hacerlo, necesitamos **definir un nombre y una descripción**. El LLM usará esta información para usar la herramienta correctamente. Veamos cómo cargar un `QueryEngineTool` usando el QueryEngine que creamos en la [sección de componentes](02_components). It is easy to **wrap `QueryEngine` as a tool** for an agent. When doing so, we need to **define a name and description**. The LLM will use this information to correctly use the tool. Let's see how to load in a `QueryEngineTool` using the `QueryEngine` we created in the [component section](02_components). ```python from llama_index.core.tools import QueryEngineTool query_engine = index.as_query_engine(llm=llm, similarity_top_k=3) # como se mostró en la sección anterior query_engine_tool = QueryEngineTool.from_defaults( query_engine=query_engine, name="nombre", description="una descripción específica", return_direct=False, ) query_engine_agent = AgentWorkflow.from_tools_or_functions( [query_engine_tool], llm=llm, system_prompt="Eres un asistente útil que tiene acceso a una base de datos que contiene descripciones de personas. " ) ``` ## Creando Sistemas Multi-agente La clase `AgentWorkflow` también soporta directamente sistemas multi-agente. Al darle a cada agente un nombre y una descripción, el sistema mantiene un único hablante activo, con cada agente teniendo la capacidad de pasar el control a otro agente. Al reducir el alcance de cada agente, podemos ayudar a aumentar su precisión general al responder a los mensajes del usuario. Los agentes en LlamaIndex también pueden usarse directamente como herramientas para otros agentes, para escenarios más complejos y personalizados. ```python from llama_index.core.agent.workflow import ( AgentWorkflow, FunctionAgent, ReActAgent, ) # Define algunas herramientas def add(a: int, b: int) -> int: """Suma dos números.""" return a + b def subtract(a: int, b: int) -> int: """Resta dos números.""" return a - b # Crea configuraciones de agentes # NOTA: podemos usar FunctionAgent o ReActAgent aquí. # FunctionAgent funciona para LLMs con una API de llamada de funciones. # ReActAgent funciona para cualquier LLM. calculator_agent = ReActAgent( name="calculadora", description="Realiza operaciones aritméticas básicas", system_prompt="Eres un asistente de calculadora. Usa tus herramientas para cualquier operación matemática.", tools=[add, subtract], llm=llm, ) query_agent = ReActAgent( name="búsqueda_de_información", description="Busca información sobre XYZ", system_prompt="Usa tu herramienta para consultar un sistema RAG y responder información sobre XYZ", tools=[query_engine_tool], llm=llm ) # Crea y ejecuta el flujo de trabajo agent = AgentWorkflow( agents=[calculator_agent, query_agent], root_agent="calculadora" ) # Ejecuta el sistema response = await agent.run(user_msg="¿Puedes sumar 5 y 3?") ``` > [!TIP] > ¿No has aprendido lo suficiente todavía? Hay mucho más por descubrir sobre agentes y herramientas en LlamaIndex dentro de la Introducción Básica a AgentWorkflow o la Guía de Aprendizaje de Agentes, ¡donde puedes leer más sobre streaming, serialización de contexto y humano-en-el-bucle! Ahora que entendemos los conceptos básicos de agentes y herramientas en LlamaIndex, ¡veamos cómo podemos usar LlamaIndex para **crear flujos de trabajo configurables y manejables!** ================================================ FILE: units/es/unit2/llama-index/components.mdx ================================================ # ¿Qué son los componentes en LlamaIndex? ¿Recuerdas a Alfred, nuestro útil agente mayordomo de la Unidad 1? Para ayudarnos de manera efectiva, Alfred necesita entender nuestras solicitudes y **preparar, encontrar y usar información relevante para ayudar a completar tareas.** Aquí es donde entran los componentes de LlamaIndex. Aunque LlamaIndex tiene muchos componentes, **nos centraremos específicamente en el componente `QueryEngine`**. ¿Por qué? Porque se puede usar como una herramienta de Generación Aumentada por Recuperación (RAG) para un agente. Entonces, ¿qué es RAG? Los LLMs están entrenados en enormes cuerpos de datos para aprender conocimiento general. Sin embargo, pueden no estar entrenados en datos relevantes y actualizados. RAG resuelve este problema encontrando y recuperando información relevante de tus datos y dándosela al LLM. ![RAG](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/rag.png) Ahora, piensa en como funciona Alfred: 1. Le pides a Alfred que te ayude a planear una cena 2. Alfred necesita revisar tu calendario, preferencias dietéticas y menús exitosos anteriores 3. El `QueryEngine` ayuda a Alfred a encontrar esta información y usarla para planear la cena Esto hace que el `QueryEngine` **sea un componente clave para construir flujos de trabajo RAG agentic** en LlamaIndex. Así como Alfred necesita buscar en la información de tu hogar para ser útil, cualquier agente necesita una forma de encontrar y entender datos relevantes. El `QueryEngine` proporciona exactamente esta capacidad. Ahora, profundicemos un poco más en los componentes y veamos como puedes **combinar componentes para crear un pipeline RAG.** ## Creando un pipeline RAG usando componentes > [!TIP] > Puedes seguir el código en este notebook que puedes ejecutar usando Google Colab. Hay cinco etapas clave dentro de RAG, que a su vez serán parte de la mayoría de las aplicaciones más grandes que construyas. Estas son: 1. **Carga**: esto se refiere a obtener tus datos desde donde residen -- ya sean archivos de texto, PDFs, otro sitio web, una base de datos o una API -- e incorporarlos a tu flujo de trabajo. LlamaHub proporciona cientos de integraciones para elegir. 2. **Indexación**: significa crear una estructura de datos que permita consultar la información. Para los LLMs, esto casi siempre significa crear embeddings vectoriales, que son representaciones numéricas del significado de los datos. La indexación también puede referirse a numerosas estrategias de metadatos para facilitar la búsqueda precisa de datos contextualmente relevantes basados en propiedades. 3. **Almacenamiento**: una vez que tus datos están indexados, querrás almacenar tu índice, así como otros metadatos, para evitar tener que volver a indexarlos. 4. **Consulta**: para cualquier estrategia de indexación hay muchas formas en que puedes utilizar LLMs y estructuras de datos de LlamaIndex para consultar, incluyendo subconsultas, consultas de múltiples pasos y estrategias híbridas. 5. **Evaluación**: un paso crítico en cualquier flujo es comprobar qué tan efectivo es en relación con otras estrategias, o cuando realizas cambios. La evaluación proporciona medidas objetivas de cuán precisas, fieles y rápidas son tus respuestas a las consultas. A continuación, veamos cómo podemos reproducir estas etapas usando componentes. ### Carga y embedding de documentos Como se mencionó anteriormente, LlamaIndex puede trabajar sobre tus propios datos, sin embargo, **antes de acceder a los datos, necesitamos cargarlos.** Hay tres formas principales de cargar datos en LlamaIndex: 1. `SimpleDirectoryReader`: Un cargador integrado para varios tipos de archivos desde un directorio local. 2. `LlamaParse`: LlamaParse, la herramienta oficial de LlamaIndex para el análisis de PDFs, disponible como API gestionada. 3. `LlamaHub`: Un registro de cientos de bibliotecas de carga de datos para ingerir datos desde cualquier fuente. > [!TIP] > Familiarízate con los cargadores de LlamaHub y el analizador LlamaParse para fuentes de datos más complejas. **La forma más sencilla de cargar datos es con `SimpleDirectoryReader`.** Este componente versátil puede cargar varios tipos de archivos desde una carpeta y convertirlos en objetos `Document` con los que LlamaIndex puede trabajar. Veamos cómo podemos usar `SimpleDirectoryReader` para cargar datos desde una carpeta. ```python from llama_index.core import SimpleDirectoryReader reader = SimpleDirectoryReader(input_dir="path/to/directory") documents = reader.load_data() ``` Después de cargar nuestros documentos, necesitamos dividirlos en piezas más pequeñas llamadas objetos `Node`. Un `Node` es simplemente un fragmento de texto del documento original que es más fácil de manejar para la IA, mientras que mantiene referencias al objeto `Document` original. El `IngestionPipeline` nos ayuda a crear estos nodos a través de dos transformaciones clave. 1. `SentenceSplitter` descompone los documentos en fragmentos manejables dividiéndolos en los límites naturales de las oraciones. 2. `HuggingFaceInferenceAPIEmbedding` convierte cada fragmento en embeddings numéricos - representaciones vectoriales que capturan el significado semántico de una manera que la IA puede procesar eficientemente. Este proceso nos ayuda a organizar nuestros documentos de una manera que es más útil para la búsqueda y el análisis. ```python from llama_index.core import Document from llama_index.embeddings.huggingface_api import HuggingFaceInferenceAPIEmbedding from llama_index.core.node_parser import SentenceSplitter from llama_index.core.ingestion import IngestionPipeline # crear el pipeline con transformaciones pipeline = IngestionPipeline( transformations=[ SentenceSplitter(chunk_overlap=0), HuggingFaceInferenceAPIEmbedding(model_name="BAAI/bge-small-en-v1.5"), ] ) nodes = await pipeline.arun(documents=[Document.example()]) ``` ### Almacenamiento e indexación de documentos Después de crear nuestros objetos `Node`, necesitamos indexarlos para hacerlos buscables, pero antes de poder hacerlo, necesitamos un lugar para almacenar nuestros datos. Como estamos usando un pipeline de ingesta, podemos adjuntar directamente un almacén vectorial al pipeline para poblarlo. En este caso, usaremos `Chroma` para almacenar nuestros documentos.
Instalar ChromaDB Como se introdujo en la [sección sobre LlamaHub](llama-hub), podemos instalar el almacén vectorial ChromaDB con el siguiente comando: ```bash pip install llama-index-vector-stores-chroma ```
```python import chromadb from llama_index.vector_stores.chroma import ChromaVectorStore db = chromadb.PersistentClient(path="./alfred_chroma_db") chroma_collection = db.get_or_create_collection("alfred") vector_store = ChromaVectorStore(chroma_collection=chroma_collection) pipeline = IngestionPipeline( transformations=[ SentenceSplitter(chunk_size=25, chunk_overlap=0), HuggingFaceInferenceAPIEmbedding(model_name="BAAI/bge-small-en-v1.5"), ], vector_store=vector_store, ) ``` > [!TIP] > Una visión general de los diferentes almacenes vectoriales se puede encontrar en la documentación de LlamaIndex. Aquí es donde entran los embeddings vectoriales - al incorporar tanto la consulta como los nodos en el mismo espacio vectorial, podemos encontrar coincidencias relevantes. El `VectorStoreIndex` se encarga de esto por nosotros, utilizando el mismo modelo de embedding que usamos durante la ingesta para garantizar la consistencia. Veamos cómo crear este índice a partir de nuestro almacén vectorial y embeddings: ```python from llama_index.core import VectorStoreIndex from llama_index.embeddings.huggingface_api import HuggingFaceInferenceAPIEmbedding embed_model = HuggingFaceInferenceAPIEmbedding(model_name="BAAI/bge-small-en-v1.5") index = VectorStoreIndex.from_vector_store(vector_store, embed_model=embed_model) ``` Toda la información se persiste automáticamente dentro del objeto `ChromaVectorStore` y la ruta del directorio proporcionado. ¡Genial! Ahora que podemos guardar y cargar nuestro índice fácilmente, exploremos cómo consultarlo de diferentes maneras. ### Consultando un VectorStoreIndex con prompts y LLMs Antes de poder consultar nuestro índice, necesitamos convertirlo a una interfaz de consulta. Las opciones de conversión más comunes son: - `as_retriever`: Para recuperación básica de documentos, devolviendo una lista de objetos `NodeWithScore` con puntuaciones de similitud - `as_query_engine`: Para interacciones de pregunta-respuesta simples, devolviendo una respuesta escrita - `as_chat_engine`: Para interacciones conversacionales que mantienen la memoria a través de múltiples mensajes, devolviendo una respuesta escrita utilizando el historial de chat y el contexto indexado Nos centraremos en el motor de consulta ya que es más común para interacciones tipo agente. También pasamos un LLM al motor de consulta para usarlo en la respuesta. ```python from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") query_engine = index.as_query_engine( llm=llm, response_mode="tree_summarize", ) query_engine.query("¿Cuál es el significado de la vida?") # El significado de la vida es 42 ``` ### Procesamiento de Respuestas Bajo el capó, el motor de consulta no solo usa el LLM para responder a la pregunta, sino que también utiliza un `ResponseSynthesizer` como estrategia para procesar la respuesta. Una vez más, esto es completamente personalizable, pero hay tres estrategias principales que funcionan bien de forma predeterminada: - `refine`: crear y refinar una respuesta recorriendo secuencialmente cada fragmento de texto recuperado. Esto hace una llamada LLM separada por cada Node/fragmento recuperado. - `compact` (predeterminado): similar a refinar pero concatenando los fragmentos de antemano, resultando en menos llamadas LLM. - `tree_summarize`: crear una respuesta detallada recorriendo cada fragmento de texto recuperado y creando una estructura de árbol de la respuesta. > [!TIP] > Toma control detallado de tus flujos de consulta con la API de composición de bajo nivel. Esta API te permite personalizar y ajustar cada paso del proceso de consulta para que coincida con tus necesidades exactas, lo que también se combina muy bien con Flujos de trabajo El modelo de lenguaje no siempre funcionará de manera predecible, por lo que no podemos estar seguros de que la respuesta que obtenemos sea siempre correcta. Podemos lidiar con esto **evaluando la calidad de la respuesta**. ### Evaluación y observabilidad LlamaIndex proporciona **herramientas de evaluación integradas para evaluar la calidad de la respuesta.** Estos evaluadores aprovechan los LLMs para analizar respuestas a través de diferentes dimensiones. Veamos los tres evaluadores principales disponibles: - `FaithfulnessEvaluator`: Evalúa la fidelidad de la respuesta comprobando si está respaldada por el contexto. - `AnswerRelevancyEvaluator`: Evalúa la relevancia de la respuesta comprobando si es relevante para la pregunta. - `CorrectnessEvaluator`: Evalúa la corrección de la respuesta comprobando si es correcta. ```python from llama_index.core.evaluation import FaithfulnessEvaluator query_engine = # de la sección anterior llm = # de la sección anterior # consultar índice evaluator = FaithfulnessEvaluator(llm=llm) response = query_engine.query( "¿Qué batallas tuvieron lugar en la ciudad de Nueva York durante la Revolución Americana?" ) eval_result = evaluator.evaluate_response(response=response) eval_result.passing ``` Incluso sin evaluación directa, podemos **obtener información sobre cómo está funcionando nuestro sistema a través de la observabilidad.** Esto es especialmente útil cuando estamos construyendo flujos de trabajo más complejos y queremos entender cómo está funcionando cada componente.
Instalar LlamaTrace Como se introdujo en la [sección sobre LlamaHub](llama-hub), podemos instalar el callback LlamaTrace de Arize Phoenix con el siguiente comando: ```bash pip install -U llama-index-callbacks-arize-phoenix ``` Además, necesitamos establecer la variable de entorno `PHOENIX_API_KEY` con nuestra clave API de LlamaTrace. Podemos obtenerla: - Creando una cuenta en [LlamaTrace](https://llamatrace.com/login) - Generando una clave API en la configuración de tu cuenta - Usando la clave API en el código siguiente para habilitar el seguimiento
```python import llama_index import os PHOENIX_API_KEY = "" os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = f"api_key={PHOENIX_API_KEY}" llama_index.core.set_global_handler( "arize_phoenix", endpoint="https://llamatrace.com/v1/traces" ) ``` > [!TIP] > ¿Quieres aprender más sobre los componentes y cómo usarlos? Continúa tu viaje con las Guías de Componentes o la Guía sobre RAG. Hemos visto cómo usar componentes para crear un `QueryEngine`. Ahora, ¡veamos cómo **usar el `QueryEngine` como una herramienta para un agente!** ================================================ FILE: units/es/unit2/llama-index/conclusion.mdx ================================================ # Conclusión !Felicidades por terminar el módulo `llama-index` de esta segunda Unidad 🥳 Acabas de dominar los fundamentos de `llama-index` y has visto como construir tus propias flujos de trabajo agentivos! Ahora que tienes habilidades en `llama-index`, puedes empezar a crear motores de búsqueda que resolveran tareas que te interesen. En el próximo módulo de la Unidad, aprenderas **cómo construir Agentes con LangGraph**. Finalmente, nos encantar a **saber que te parece el curso y como podemos mejorar**. Si tienes alguna retroalimentación, por favor 👉 llena este formulario: [https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ### Sigue aprendiendo, y sigue siendo increible 🤗 ================================================ FILE: units/es/unit2/llama-index/introduction.mdx ================================================ # Introducción a LlamaIndex Bienvenido a este módulo, donde aprenderás a construir agentes impulsados por LLM utilizando el kit de herramientas de [LlamaIndex](https://www.llamaindex.ai/). LlamaIndex es **un kit de herramientas completo para crear agentes impulsados por LLM sobre tus datos utilizando índices y flujos de trabajo**. En este curso, nos centraremos en tres partes principales que ayudan a construir agentes en LlamaIndex: **Componentes**, **Herramientas y Agentes** y **Flujos de trabajo**. ![LlamaIndex](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/thumbnail.png) Echemos un vistazo a estas partes clave de LlamaIndex y cómo ayudan a construir agentes: - **Componentes** son los bloques de construcción básicos que se utilizan en LlamaIndex. Estos incluyen cosas como prompts, modelos y bases de datos. Los componentes suelen ayudar a conectar LlamaIndex con otras herramientas y bibliotecas. - **Herramientas**: Las herramientas son componentes que proporcionan capacidades específicas como búsqueda, cálculo o acceso a servicios externos. Son los bloques de construcción que permiten a los agentes realizar tareas. - **Agentes**: Los agentes son componentes autónomos que pueden utilizar herramientas y tomar decisiones. Coordinan el uso de herramientas para lograr objetivos complejos. - **Flujos de trabajo** son procesos paso a paso que procesan lógica juntos. Los flujos de trabajo o flujos de trabajo agentivos son una forma de estructurar el comportamiento agente sin el uso explícito de agentes. ## ¿Qué hace que LlamaIndex sea especial? Aunque LlamaIndex hace algunas cosas similares a otros frameworks como smolagents, tiene algunas ventajas clave: - **Sistema de flujo de trabajo claro**. Los flujos de trabajo ayudan a descomponer cómo los agentes deben tomar decisiones paso a paso utilizando una sintaxis de eventos y async-first. Esto te ayuda a organizar y componer tu lógica de manera clara. - **Análisis de documentos avanzado con LlamaParse** LlamaParse se creó específicamente para LlamaIndex, por lo que la integración es perfecta, aunque es una característica de pago. - **Muchos componentes listos para usar** LlamaIndex ha estado disponible durante un tiempo, por lo que funciona con muchos otros frameworks. Esto significa que tiene muchos componentes probados y confiables, como LLMs, recuperadores, índices y más. - **LlamaHub** es un registro de cientos de estos componentes, agentes y herramientas que puedes utilizar dentro de LlamaIndex. Todos estos conceptos son necesarios en diferentes escenarios para crear agentes útiles. En las siguientes secciones, exploraremos cada uno de estos conceptos en detalle. Después de dominar los conceptos, utilizaremos lo que hemos aprendido para **crear casos de uso aplicados con Alfred el agente**! ¿Estás emocionado de empezar a trabajar con LlamaIndex? ¡Vamos a empezar a **buscar e instalar las integraciones que necesitamos utilizando LlamaHub! 🚀** ================================================ FILE: units/es/unit2/llama-index/llama-hub.mdx ================================================ # Introducción a LlamaHub **LlamaHub es un registro de cientos de integraciones, agentes y herramientas que puedes utilizar dentro de LlamaIndex.** ![LlamaHub](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/llama-hub.png) Vamos a utilizar varias integraciones en este curso, así que primero echaremos un vistazo a LlamaHub y veremos cómo puede ayudarnos. Vamos a ver cómo encontrar e instalar las dependencias para los componentes que necesitamos. ## Instalación Las instrucciones de instalación de LlamaIndex están disponibles en **[LlamaHub](https://llamahub.ai/)**. Puede parecer un poco abrumador al principio, pero la mayoría de los comandos de **instalación siguen un formato fácil de recordar **: ```bash pip install llama-index-{component-type}-{framework-name} ``` Vamos a intentar instalar las dependencias para un componente de LLM utilizando la [integración de la API de inferencia de Hugging Face](https://llamahub.ai/l/llms/llama-index-llms-huggingface-api?from=llms). ```bash pip install llama-index-llms-huggingface-api ``` ## Uso Una vez instalado, podemos ver los patrones de uso. Notaras que los caminos de importación siguen el comando de instalación! Debajo, podemos ver un ejemplo de la utilización de **la API de inferencia de Hugging Face para un componente LLM**. ```python from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI llm = HuggingFaceInferenceAPI( model_name="Qwen/Qwen2.5-Coder-32B-Instruct", temperature=0.7, max_tokens=100, token="hf_xxx", ) llm.completar(" Hola, cómo estás?") # Estoy bien, ¿cómo puedo ayudarte hoy? ``` Genial, ahora sabemos como encontrar, instalar y utilizar las integraciones para los componentes que necesitamos. **Vamos a profundizar en los componentes** y veremos como podemos utilizarlos para construir nuestros propios agentes. ================================================ FILE: units/es/unit2/llama-index/quiz1.mdx ================================================ # Pequeño Quiz (no calificado) [[quiz1]] Hasta ahora hemos discutido los componentes clave y herramientas utilizadas en LlamaIndex. Es hora de hacer un pequeño quiz, ya que **probarse a sí mismo** es la mejor manera de aprender y [evitar la ilusi n de competencia](https://www.coursera.org/lecture/learning-how-to-learn/illusions-of-competence-BuFzf). Esto te ayudar a encontrar **dónde debes reforzar tus conocimientos**. Este es un quiz opcional y no está calificado. ### Q1: ¿Qué es un QueryEngine? ¿Cuál de las siguientes opciones describe mejor un componente QueryEngine? --- ### Q2: ¿Cuál es el propósito de FunctionTools? ¿Por qué son importantes FunctionTools para un Agente? --- ### Q3: ¿Qué son los Toolspecs en LlamaIndex? ¿Cuál es el propósito principal de los Toolspecs? --- ### Q4: ¿Qué se requiere para crear una herramienta? ¿Qué información debe incluirse al crear una herramienta? --- !Felicitaciones por completar este Quiz 🥳!, si no entendiste algün elemento, tóoma el tiempo de releer el capítulo para reforzar tus conocimientos. Si lo pasaste, estás listo para profundizar en el uso de estos componentes! ================================================ FILE: units/es/unit2/llama-index/quiz2.mdx ================================================ # Autoevaluación Rápida (sin calificar) [[quiz2]] ¿Qué?! Otra autoevaluación? Lo sabemos, lo sabemos, ... 😅 Pero esta breve autoevaluación no calificada está aquí para **ayudarte a reforzar conceptos clave que acabas de aprender**. Esta evaluación cubre flujos de trabajo de agentes y interacciones - componentes esenciales para construir agentes de IA efectivos. ### Q1: ¿Cuál es el propósito de AgentWorkflow en LlamaIndex? --- ### Q2: ¿Qué objeto se utiliza para mantener el estado del flujo de trabajo? --- ### Q3: ¿Qué método debe utilizarse si deseas que un agente recuerde interacciones previas? --- ### Q4: ¿Qué es una característica clave de Agentic RAG? --- ¿Entendido? Genial! Ahora hagamos un **resumen breve de la unidad!** ================================================ FILE: units/es/unit2/llama-index/tools.mdx ================================================ # Uso de Herramientas en LlamaIndex **Definir un conjunto claro de herramientas es crucial para el rendimiento.** Como discutimos en [unidad 1](../../unit1/tools), las interfaces de herramientas claras son más fáciles de usar para los LLM. Al igual que una interfaz de API para ingenieros humanos, pueden obtener m s de la herramienta si es f cil de entender c mo funciona. Hay **cuatro tipos principales de herramientas en LlamaIndex**: ![Herramientas](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/tools.png) 1. `FunctionTool`: Convierte cualquier función de Python en una herramienta que un agente puede utilizar. Averigua autom ticamente cómo funciona. 2. `QueryEngineTool`: Una herramienta que permite a los agentes utilizar motores de consulta. Dado que los agentes est n construidos sobre motores de consulta, también pueden utilizar a otros agentes como herramientas. 3. `Toolspecs`: Conjuntos de herramientas creados por la comunidad, que a menudo incluyen herramientas para servicios específicos como Gmail. 4. `Utility Tools`: Herramientas especiales que ayudan a manejar grandes cantidades de datos de otras herramientas. Vamos a ver cada una de ellas en más detalle a continuación. ## Crear una FunctionTool > [!TIP] > Puedes seguir el código en este cuaderno que puedes ejecutar utilizando Google Colab. Una FunctionTool proporciona una forma sencilla de envolver cualquier función de Python y hacerla disponible para un agente. Puedes pasar tanto una función sincrónica como asincrona a la herramienta, junto con par metros opcionales `name` y `description`. El nombre y la descripción son particularmente importantes, ya que ayudan al agente a entender cuando y cómo utilizar la herramienta de manera efectiva. Vamos a ver cómo crear una FunctionTool a continuación y luego llamarla. ```python from llama_index.core.tools import FunctionTool def get_weather(location: str) -> str: """Útil para obtener el clima para una ubicación determinada.""" print(f"Obtener clima de {location}") return f"El clima en {location} es soleado" tool = FunctionTool.from_defaults( get_weather, name="my_weather_tool", description="Útil para obtener el clima para una ubicación determinada.", ) tool.call("Nuevo York") ``` > [!TIP] > Cuando se utiliza un agente o LLM con llamadas a funciones, la herramienta seleccionada (y los argumentos escritos para esa herramienta) dependen en gran medida del nombre de la herramienta y la descripción del proposito y argumentos de la herramienta. Aprende más sobre la llamada a funciones en la Guía de llamada a funciones. ## Creando un QueryEngineTool The `QueryEngine` que definimos en la unidad anterior puede ser facilmente transformado en una herramienta usando la clase `QueryEngineTool`. Vamos a ver como crear un `QueryEngineTool` desde un `QueryEngine` en el ejemplo siguiente. ```python from llama_index.core import VectorStoreIndex from llama_index.core.tools import QueryEngineTool from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI from llama_index.embeddings.huggingface_api import HuggingFaceInferenceAPIEmbedding from llama_index.vector_stores.chroma import ChromaVectorStore embed_model = HuggingFaceInferenceAPIEmbedding("BAAI/bge-small-en-v1.5") db = chromadb.PersistentClient(path="./alfred_chroma_db") chroma_collection = db.get_or_create_collection("alfred") vector_store = ChromaVectorStore(chroma_collection=chroma_collection) index = VectorStoreIndex.from_vector_store(vector_store, embed_model=embed_model) llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") query_engine = index.as_query_engine(llm=llm) tool = QueryEngineTool.from_defaults(query_engine, name="some useful name", description="some useful description") ``` ## Crear Herramientas Especificas Piensa en `ToolSpecs` como colecciones de herramientas que trabajan juntas armoniosamente - como una caja de herramientas bien organizada de un profesional. Al igual que una caja de herramientas de un mecanico contiene herramientas complementarias que trabajan juntas para reparaciones de vehiculos, un `ToolSpec` combina herramientas relacionadas para un proposito especifico. Por ejemplo, la herramienta especifica de un agente contable podria combinar elegante mente capacidades de hoja de calculo, funcionalidad de correo electronico y herramientas de calculo para manejar tareas financieras con precision y eficiencia.
Instalar la herramienta especifica de Google Como se introdujo en la [seccion sobre LlamaHub](llama-hub), podemos instalar la herramienta especifica de Google con el siguiente comando: ```python pip install llama-index-tools-google ```
Y ahora podemos cargar la herramienta especifica y convertirla en una lista de herramientas. ```python from llama_index.tools.google import GmailToolSpec tool_spec = GmailToolSpec() tool_spec_list = tool_spec.to_tool_list() Para obtener una visión más detallada de las herramientas, podemos examinar los `metadata` de cada una de ellas. ```python [(tool.metadata.name, tool.metadata.description) for tool in tool_spec_list] ``` ## Herramientas de utilidad A menudo, realizar consultas a una API **puede devolver una cantidad excesiva de datos**, algunos de los cuales pueden ser irrelevantes, desbordar la ventana de contexto del LLM o aumentar innecesariamente el número de tokens que se están utilizando. Vamos a revisar nuestras dos principales herramientas de utilidad a continuaci n. 1. `OnDemandToolLoader`: Esta herramienta convierte cualquier cargador de datos existente de LlamaIndex (clase BaseReader) en una herramienta que un agente puede utilizar. La herramienta se puede llamar con todos los parámetros necesarios para desencadenar `load_data` del cargador de datos, junto con una cadena de consulta de lenguaje natural. Durante la ejecución, primero cargamos datos del cargador de datos, los indexamos (por ejemplo, con un vector store) y luego los consultamos. Todos estos tres pasos se realizan en una sola llamada a la herramienta. 2. `LoadAndSearchToolSpec`: El LoadAndSearchToolSpec toma cualquier herramienta existente como entrada. Como herramienta específicas, implementa `to_tool_list`, y cuando se llama a esa función, se devuelven dos herramientas: una herramienta de carga y una herramienta de búsqueda. La ejecución de la herramienta de carga llamar a la herramienta subyacente, y luego indexar la salida (por defecto con un vector index). La ejecución de la herramienta de búsqueda tomar una cadena de consulta como entrada y llamar al vector index subyacente. > [!TIP] > Puedes encontrar herramientas y herramientas de utilidad en LlamaHub Ahora que entendemos los conceptos básicos de agentes y herramientas en LlamaIndex, veamos cómo podemos **usar LlamaIndex para crear flujos de trabajo configurables y manejables!** ================================================ FILE: units/es/unit2/llama-index/workflows.mdx ================================================ # Crear workflows agenticos en LlamaIndex Un workflow en LlamaIndex proporciona una forma estructurada de organizar su código en pasos secuenciales y manejables. Tal workflow se crea definiendo `Steps` que se activan por `Events`, y emiten `Events` para activar pasos posteriores. Echemos un vistazo a Alfred mostrando un workflow de LlamaIndex para una tarea de RAG. ![Workflows esquematico](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/workflows.png) **Workflows ofrecen varios beneficios clave:** - Organizacion clara de código en pasos discretos - Arquitectura de control de flujo basada en eventos flexible - Comunicación de tipado segura entre pasos - Manejo de estado integrado - Apoyo para agentes simples y complejos Como podra haber adivinado, **workflows ofrecen un equilibrio entre la autonomía de los agentes mientras se mantiene el control sobre el workflow global.** Asi que, vamos a aprender como crear un workflow nosotros mismos! ## Crear Workflows > [!TIP] > Puede seguir el código en esta notebook que puede ejecutar utilizando Google Colab. ### Crear un workflow básico
Instalar el paquete Workflow Como se introdujo en la [sección sobre LlamaHub](llama-hub), podemos instalar el paquete Workflow con el siguiente comando: ```python pip install llama-index-utils-workflow ```
Podemos crear un flujo de trabajo de un solo paso definiendo una clase que herede de `Workflow` y decorando tus funciones con `@step`. También necesitaremos añadir `StartEvent` y `StopEvent`, que son eventos especiales que se utilizan para indicar el inicio y el fin del flujo de trabajo. ```python from llama_index.core.workflow import StartEvent, StopEvent, Workflow, step class MyWorkflow(Workflow): @step async def my_step(self, ev: StartEvent) -> StopEvent: # hacer algo aquí return StopEvent(result="¡Hola, mundo!") w = MyWorkflow(timeout=10, verbose=False) result = await w.run() ``` Como puedes ver, ahora podemos ejecutar el flujo de trabajo llamando a `w.run()`. ### Conectando Múltiples Pasos Para conectar múltiples pasos, **creamos eventos personalizados que transportan datos entre pasos.** Para hacerlo, necesitamos agregar un `Event` que se pasa entre los pasos y transfiere la salida del primer paso al segundo paso. ```python from llama_index.core.workflow import Event class ProcessingEvent(Event): intermediate_result: str class MultiStepWorkflow(Workflow): @step async def step_one(self, ev: StartEvent) -> ProcessingEvent: # Procesar datos iniciales return ProcessingEvent(intermediate_result="Paso 1 completado") @step async def step_two(self, ev: ProcessingEvent) -> StopEvent: # Usar el resultado intermedio final_result = f"Procesamiento finalizado: {ev.intermediate_result}" return StopEvent(result=final_result) w = MultiStepWorkflow(timeout=10, verbose=False) result = await w.run() result ``` La indicación de tipo es importante aquí, ya que asegura que el flujo de trabajo se ejecute correctamente. ¡Vamos a complicar un poco más las cosas! ### Bucles y Ramificaciones La indicación de tipo es la parte más poderosa de los flujos de trabajo porque nos permite crear ramificaciones, bucles y uniones para facilitar flujos de trabajo más complejos. Veamos un ejemplo de **creación de un bucle** usando el operador de unión `|`. En el ejemplo siguiente, vemos que el `LoopEvent` se toma como entrada para el paso y también puede devolverse como salida. ```python from llama_index.core.workflow import Event import random class ProcessingEvent(Event): intermediate_result: str class LoopEvent(Event): loop_output: str class MultiStepWorkflow(Workflow): @step async def step_one(self, ev: StartEvent) -> ProcessingEvent | LoopEvent: if random.randint(0, 1) == 0: print("Ocurrió algo malo") return LoopEvent(loop_output="Volver al paso uno.") else: print("Ocurrió algo bueno") return ProcessingEvent(intermediate_result="Primer paso completado.") @step async def step_two(self, ev: ProcessingEvent | LoopEvent) -> StopEvent: # Usar el resultado intermedio final_result = f"Procesamiento finalizado: {ev.intermediate_result}" return StopEvent(result=final_result) w = MultiStepWorkflow(verbose=False) result = await w.run() result ``` ### Dibujando Flujos de Trabajo También podemos dibujar flujos de trabajo. Usemos la función `draw_all_possible_flows` para dibujar el flujo de trabajo. Esto almacena el flujo de trabajo en un archivo HTML. ```python from llama_index.utils.workflow import draw_all_possible_flows w = ... # como se definió en la sección anterior draw_all_possible_flows(w, "flow.html") ``` ![dibujo del flujo de trabajo](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/workflow-draw.png) Hay un último truco interesante que cubriremos en el curso, que es la capacidad de añadir estado al flujo de trabajo. ### Gestión de Estado La gestión de estado es útil cuando quieres hacer un seguimiento del estado del flujo de trabajo, para que cada paso tenga acceso al mismo estado. Podemos hacer esto usando la pista de tipo `Context` encima de un parámetro en la función del paso. ```python from llama_index.core.workflow import Context, StartEvent, StopEvent @step async def query(self, ctx: Context, ev: StartEvent) -> StopEvent: # almacenar en contexto await ctx.store.set("query", "¿Cuál es la capital de Francia?") # hacer algo con el contexto y el evento val = ... # recuperar del contexto query = await ctx.store.get("query") return StopEvent(result=result) ``` ¡Genial! ¡Ahora sabes cómo crear flujos de trabajo básicos en LlamaIndex! > [!TIP] > Hay algunos matices más complejos en los flujos de trabajo, que puedes aprender en la documentación de LlamaIndex. Sin embargo, hay otra forma de crear flujos de trabajo, que se basa en la clase `AgentWorkflow`. Veamos cómo podemos usar esto para crear un flujo de trabajo multiagente. ## Automatizando flujos de trabajo con Flujos de Trabajo Multiagente En lugar de la creación manual de flujos de trabajo, podemos usar la clase **`AgentWorkflow` para crear un flujo de trabajo multiagente**. El `AgentWorkflow` utiliza Agentes de Flujo de Trabajo para permitirte crear un sistema de uno o más agentes que pueden colaborar y transferir tareas entre sí según sus capacidades especializadas. Esto permite construir sistemas de agentes complejos donde diferentes agentes manejan diferentes aspectos de una tarea. En lugar de importar clases de `llama_index.core.agent`, importaremos las clases de agente de `llama_index.core.agent.workflow`. Un agente debe ser designado como el agente raíz en el constructor de `AgentWorkflow`. Cuando llega un mensaje de usuario, primero se dirige al agente raíz. Cada agente puede entonces: - Manejar la solicitud directamente usando sus herramientas - Transferir a otro agente mejor preparado para la tarea - Devolver una respuesta al usuario Veamos cómo crear un flujo de trabajo multiagente. ```python from llama_index.core.agent.workflow import AgentWorkflow, ReActAgent from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI # Definir algunas herramientas def add(a: int, b: int) -> int: """Sumar dos números.""" return a + b def multiply(a: int, b: int) -> int: """Multiplicar dos números.""" return a * b llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") # podemos pasar funciones directamente sin FunctionTool -- la función/docstring se analizan para el nombre/descripción multiply_agent = ReActAgent( name="multiply_agent", description="Es capaz de multiplicar dos enteros", system_prompt="Un asistente útil que puede usar una herramienta para multiplicar números.", tools=[multiply], llm=llm, ) addition_agent = ReActAgent( name="add_agent", description="Es capaz de sumar dos enteros", system_prompt="Un asistente útil que puede usar una herramienta para sumar números.", tools=[add], llm=llm, ) # Crear el flujo de trabajo workflow = AgentWorkflow( agents=[multiply_agent, addition_agent], root_agent="multiply_agent", ) # Ejecutar el sistema response = await workflow.run(user_msg="¿Puedes sumar 5 y 3?") ``` Las herramientas del agente también pueden modificar el estado del flujo de trabajo que mencionamos anteriormente. Antes de iniciar el flujo de trabajo, podemos proporcionar un diccionario de estado inicial que estará disponible para todos los agentes. El estado se almacena en la clave state del contexto del flujo de trabajo. Se inyectará en el state_prompt que aumenta cada nuevo mensaje de usuario. Vamos a inyectar un contador para contar las llamadas a funciones modificando el ejemplo anterior: ```python from llama_index.core.workflow import Context # Definir algunas herramientas async def add(ctx: Context, a: int, b: int) -> int: """Sumar dos números.""" # actualizar nuestro contador cur_state = await ctx.store.get("state") cur_state["num_fn_calls"] += 1 await ctx.store.set("state", cur_state) return a + b async def multiply(ctx: Context, a: int, b: int) -> int: """Multiplicar dos números.""" # actualizar nuestro contador cur_state = await ctx.store.get("state") cur_state["num_fn_calls"] += 1 await ctx.store.set("state", cur_state) return a * b ... workflow = AgentWorkflow( agents=[multiply_agent, addition_agent], root_agent="multiply_agent" initial_state={"num_fn_calls": 0}, state_prompt="Estado actual: {state}. Mensaje del usuario: {msg}", ) # ejecutar el flujo de trabajo con contexto ctx = Context(workflow) response = await workflow.run(user_msg="¿Puedes sumar 5 y 3?", ctx=ctx) # extraer e inspeccionar el estado state = await ctx.store.get("state") print(state["num_fn_calls"]) ``` ¡Felicidades! ¡Ahora has dominado los conceptos básicos de los Agentes en LlamaIndex! 🎉 ¡Continuemos con un último cuestionario para consolidar tu conocimiento! 🚀 ================================================ FILE: units/es/unit2/smolagents/code_agents.mdx ================================================ # Construcción de Agentes que Usan Código Los agentes de código son el tipo de agente predeterminado en `smolagents`. Generan llamadas a herramientas en Python para realizar acciones, logrando representaciones de acciones que son eficientes, expresivas y precisas. Su enfoque simplificado reduce el número de acciones requeridas, simplifica operaciones complejas y permite la reutilización de funciones de código existentes. `smolagents` proporciona un marco ligero para construir agentes de código, implementado en aproximadamente 1,000 líneas de código. ![Acciones de Código vs JSON](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/code_vs_json_actions.png) Gráfico del artículo [Executable Code Actions Elicit Better LLM Agents](https://huggingface.co/papers/2402.01030) > [!TIP] > Si quieres aprender más sobre por qué los agentes de código son efectivos, consulta esta guía de la documentación de smolagents. ## ¿Por qué Agentes de Código? En un proceso de agente de múltiples pasos, el LLM escribe y ejecuta acciones, típicamente involucrando llamadas a herramientas externas. Los enfoques tradicionales utilizan un formato JSON para especificar nombres de herramientas y argumentos como cadenas de texto, **que el sistema debe analizar para determinar qué herramienta ejecutar**. Sin embargo, la investigación muestra que **los LLMs que llaman a herramientas funcionan más efectivamente con código directamente**. Este es un principio fundamental de `smolagents`, como se muestra en el diagrama anterior del artículo [Executable Code Actions Elicit Better LLM Agents](https://huggingface.co/papers/2402.01030). Escribir acciones en código en lugar de JSON ofrece varias ventajas clave: * **Componibilidad**: Combinar y reutilizar acciones fácilmente * **Gestión de Objetos**: Trabajar directamente con estructuras complejas como imágenes * **Generalidad**: Expresar cualquier tarea computacionalmente posible * **Natural para LLMs**: Código de alta calidad ya está presente en los datos de entrenamiento de LLMs ## ¿Cómo Funciona un Agente de Código? ![De https://huggingface.co/docs/smolagents/conceptual_guides/react](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/smolagents/codeagent_docs.png) El diagrama anterior ilustra cómo funciona `CodeAgent.run()`, siguiendo el marco ReAct que mencionamos en la Unidad 1. La abstracción principal para agentes en `smolagents` es un `MultiStepAgent`, que sirve como el bloque de construcción central. `CodeAgent` es un tipo especial de `MultiStepAgent`, como veremos en un ejemplo a continuación. Un `CodeAgent` realiza acciones a través de un ciclo de pasos, con variables y conocimientos existentes incorporados en el contexto del agente, que se mantiene en un registro de ejecución: 1. El prompt del sistema se almacena en un `SystemPromptStep`, y la consulta del usuario se registra en un `TaskStep`. 2. Luego, se ejecuta el siguiente bucle while: 2.1 El método `agent.write_memory_to_messages()` escribe los registros del agente en una lista de [mensajes de chat](https://huggingface.co/docs/transformers/en/chat_templating) legibles por el LLM. 2.2 Estos mensajes se envían a un `Model`, que genera una finalización. 2.3 La finalización se analiza para extraer la acción, que, en nuestro caso, debería ser un fragmento de código ya que estamos trabajando con un `CodeAgent`. 2.4 La acción se ejecuta. 2.5 Los resultados se registran en la memoria en un `ActionStep`. Al final de cada paso, si el agente incluye alguna llamada a función (en `agent.step_callback`), estas se ejecutan. ## Veamos Algunos Ejemplos > [!TIP] > Puedes seguir el código en este notebook que puedes ejecutar usando Google Colab. Alfred está planeando una fiesta en la mansión de la familia Wayne y necesita tu ayuda para asegurarse de que todo salga bien. Para ayudarlo, aplicaremos lo que hemos aprendido sobre cómo opera un `CodeAgent` de múltiples pasos. Fiesta de Alfred Si aún no has instalado `smolagents`, puedes hacerlo ejecutando el siguiente comando: ```bash pip install smolagents -U ``` También iniciemos sesión en el Hugging Face Hub para tener acceso a la API de Inferencia Serverless. ```python from huggingface_hub import login login() ``` ### Seleccionando una Lista de Reproducción para la Fiesta Usando `smolagents` ¡La música es una parte esencial de una fiesta exitosa! Alfred necesita ayuda para seleccionar la lista de reproducción. Por suerte, ¡`smolagents` nos tiene cubiertos! Podemos construir un agente capaz de buscar en la web usando DuckDuckGo. Para dar al agente acceso a esta herramienta, la incluimos en la lista de herramientas al crear el agente. Lista de reproducción de Alfred Para el modelo, confiaremos en `InferenceClientModel`, que proporciona acceso a la [API de Inferencia Serverless](https://huggingface.co/docs/api-inference/index) de Hugging Face. El modelo predeterminado es `"Qwen/Qwen2.5-Coder-32B-Instruct"`, que es eficiente y está disponible para inferencia rápida, pero puedes seleccionar cualquier modelo compatible del Hub. Ejecutar un agente es bastante sencillo: ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel agent = CodeAgent(tools=[DuckDuckGoSearchTool()], model=InferenceClientModel()) agent.run("Busca las mejores recomendaciones de música para una fiesta en la mansión de los Wayne.") ``` Cuando ejecutes este ejemplo, la salida **mostrará un seguimiento de los pasos del flujo de trabajo siendo ejecutados**. También imprimirá el código Python correspondiente con el mensaje: ```python ─ Ejecutando código analizado: ──────────────────────────────────────────────────────────────────────────────────── results = web_search(query="mejor música para una fiesta de Batman") print(results) ───────────────────────────────────────────────────────────────────────────────────────────────────────────────── ``` ¡Después de algunos pasos, verás la lista de reproducción generada que Alfred puede usar para la fiesta! 🎵 ### Usando una Herramienta Personalizada para Preparar el Menú Menú de Alfred Ahora que hemos seleccionado una lista de reproducción, necesitamos organizar el menú para los invitados. De nuevo, Alfred puede aprovechar `smolagents` para hacerlo. Aquí, usamos el decorador `@tool` para definir una función personalizada que actúa como herramienta. Cubriremos la creación de herramientas con más detalle más adelante, así que por ahora, simplemente podemos ejecutar el código. Como puedes ver en el ejemplo a continuación, crearemos una herramienta usando el decorador `@tool` y la incluiremos en la lista de `tools`. ```python from smolagents import CodeAgent, tool, InferenceClientModel # Herramienta para sugerir un menú basado en la ocasión @tool def suggest_menu(occasion: str) -> str: """ Sugiere un menú basado en la ocasión. Args: occasion: El tipo de ocasión para la fiesta. """ if occasion == "casual": return "Pizza, aperitivos y bebidas." elif occasion == "formal": return "Cena de 3 platos con vino y postre." elif occasion == "superhero": return "Buffet con comida saludable y de alta energía." else: return "Menú personalizado para el mayordomo." # Alfred, el mayordomo, preparando el menú para la fiesta agent = CodeAgent(tools=[suggest_menu], model=InferenceClientModel()) # Preparando el menú para la fiesta agent.run("Prepara un menú formal para la fiesta.") ``` El agente se ejecutará durante algunos pasos hasta encontrar la respuesta. ¡El menú está listo! 🥗 ### Usando Importaciones de Python Dentro del Agente Tenemos la lista de reproducción y el menú listos, pero necesitamos verificar un detalle más crucial: ¡el tiempo de preparación! Alfred necesita calcular cuándo todo estaría listo si comenzara a preparar ahora, en caso de que necesiten asistencia de otros superhéroes. `smolagents` se especializa en agentes que escriben y ejecutan fragmentos de código Python, ofreciendo ejecución en sandbox para seguridad. **La ejecución de código tiene medidas de seguridad estrictas** - las importaciones fuera de una lista predefinida segura están bloqueadas por defecto. Sin embargo, puedes autorizar importaciones adicionales pasándolas como cadenas en `additional_authorized_imports`. Para más detalles sobre la ejecución segura de código, consulta la [guía](https://huggingface.co/docs/smolagents/tutorials/secure_code_execution) oficial. Al crear el agente, usaremos `additional_authorized_imports` para permitir la importación del módulo `datetime`. ```python from smolagents import CodeAgent, InferenceClientModel import numpy as np import time import datetime agent = CodeAgent(tools=[], model=InferenceClientModel(), additional_authorized_imports=['datetime']) agent.run( """ Alfred necesita prepararse para la fiesta. Aquí están las tareas: 1. Preparar las bebidas - 30 minutos 2. Decorar la mansión - 60 minutos 3. Configurar el menú - 45 minutos 4. Preparar la música y la lista de reproducción - 45 minutos Si comenzamos ahora mismo, ¿a qué hora estará lista la fiesta? """ ) ``` Estos ejemplos son solo el comienzo de lo que puedes hacer con agentes de código, y ya estamos empezando a ver su utilidad para preparar la fiesta. Puedes aprender más sobre cómo construir agentes de código en la [documentación de smolagents](https://huggingface.co/docs/smolagents). En resumen, `smolagents` se especializa en agentes que escriben y ejecutan fragmentos de código Python, ofreciendo ejecución en sandbox para seguridad. Soporta modelos de lenguaje tanto locales como basados en API, haciéndolo adaptable a varios entornos de desarrollo. ### Compartiendo Nuestro Agente Preparador de Fiestas Personalizado en el Hub ¿No sería **increíble compartir nuestro propio agente Alfred con la comunidad**? Al hacerlo, cualquiera puede descargar y usar fácilmente el agente directamente desde el Hub, ¡llevando el mejor planificador de fiestas de Gotham a sus manos! ¡Hagámoslo posible! 🎉 La biblioteca `smolagents` hace esto posible al permitirte compartir un agente completo con la comunidad y descargar otros para uso inmediato. Es tan simple como lo siguiente: ```python # Cambia a tu nombre de usuario y nombre de repositorio agent.push_to_hub('sergiopaniego/AlfredAgent') ``` Para descargar el agente nuevamente, usa el código a continuación: ```python # Cambia a tu nombre de usuario y nombre de repositorio alfred_agent = agent.from_hub('sergiopaniego/AlfredAgent') alfred_agent.run("Dame la mejor lista de reproducción para una fiesta en la mansión de Wayne. La idea de la fiesta es un tema de 'mascarada de villanos'") ``` Lo que también es emocionante es que los agentes compartidos están directamente disponibles como Hugging Face Spaces, permitiéndote interactuar con ellos en tiempo real. Puedes explorar otros agentes [aquí](https://huggingface.co/spaces/davidberenstein1957/smolagents-and-tools). Por ejemplo, el _AlfredAgent_ está disponible [aquí](https://huggingface.co/spaces/sergiopaniego/AlfredAgent). Puedes probarlo directamente a continuación: Tal vez te preguntes: ¿cómo construyó Alfred un agente así usando `smolagents`? Al integrar varias herramientas, puede generar un agente de la siguiente manera. No te preocupes por las herramientas por ahora, ya que tendremos una sección dedicada más adelante en esta unidad para explorar eso en detalle: ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, FinalAnswerTool, InferenceClientModel, Tool, tool, VisitWebpageTool @tool def suggest_menu(occasion: str) -> str: """ Sugiere un menú basado en la ocasión. Args: occasion: El tipo de ocasión para la fiesta. """ if occasion == "casual": return "Pizza, aperitivos y bebidas." elif occasion == "formal": return "Cena de 3 platos con vino y postre." elif occasion == "superhero": return "Buffet con comida saludable y de alta energía." else: return "Menú personalizado para el mayordomo." @tool def catering_service_tool(query: str) -> str: """ Esta herramienta devuelve el servicio de catering mejor calificado en Ciudad Gótica. Args: query: Un término de búsqueda para encontrar servicios de catering. """ # Lista de ejemplo de servicios de catering y sus calificaciones services = { "Gotham Catering Co.": 4.9, "Wayne Manor Catering": 4.8, "Gotham City Events": 4.7, } # Encuentra el servicio de catering mejor calificado (simulando filtrado de consulta de búsqueda) best_service = max(services, key=services.get) return best_service class SuperheroPartyThemeTool(Tool): name = "superhero_party_theme_generator" description = """ Esta herramienta sugiere ideas creativas para fiestas temáticas de superhéroes basadas en una categoría. Devuelve una idea única de tema para la fiesta.""" inputs = { "category": { "type": "string", "description": "El tipo de fiesta de superhéroes (por ejemplo, 'héroes clásicos', 'mascarada de villanos', 'Gotham futurista').", } } output_type = "string" def forward(self, category: str): themes = { "classic heroes": "Gala de la Liga de la Justicia: Los invitados vienen vestidos como sus héroes favoritos de DC con cócteles temáticos como 'El Ponche de Kryptonita'.", "villain masquerade": "Baile de los Pícaros de Gotham: Una mascarada misteriosa donde los invitados se visten como villanos clásicos de Batman.", "futuristic Gotham": "Noche Neo-Gotham: Una fiesta de estilo cyberpunk inspirada en Batman Beyond, con decoraciones de neón y gadgets futuristas." } return themes.get(category.lower(), "Idea de fiesta temática no encontrada. Prueba con 'héroes clásicos', 'mascarada de villanos' o 'Gotham futurista'.") # Alfred, el mayordomo, preparando el menú para la fiesta agent = CodeAgent( tools=[ DuckDuckGoSearchTool(), VisitWebpageTool(), suggest_menu, catering_service_tool, SuperheroPartyThemeTool() ], model=InferenceClientModel(), max_steps=10, verbosity_level=2 ) agent.run("Dame la mejor lista de reproducción para una fiesta en la mansión de Wayne. La idea de la fiesta es un tema de 'mascarada de villanos'") ``` Como puedes ver, hemos creado un `CodeAgent` con varias herramientas que mejoran la funcionalidad del agente, ¡convirtiéndolo en el mejor planificador de fiestas listo para compartir con la comunidad! 🎉 Ahora, es tu turno: ¡construye tu propio agente y compártelo con la comunidad usando el conocimiento que acabamos de aprender! 🕵️‍♂️💡 > [!TIP] > Si deseas compartir tu proyecto de agente, entonces crea un space y etiqueta a [agents-course](https://huggingface.co/agents-course) en el Hugging Face Hub. ¡Nos encantaría ver lo que has creado! ### Inspeccionando Nuestro Agente Preparador de Fiestas con OpenTelemetry y Langfuse 📡 A medida que Alfred perfecciona el Agente Preparador de Fiestas, se está cansando de depurar sus ejecuciones. Los agentes, por naturaleza, son impredecibles y difíciles de inspeccionar. Pero como su objetivo es construir el mejor Agente Preparador de Fiestas y desplegarlo en producción, necesita una trazabilidad robusta para monitoreo y análisis futuros. ¡Una vez más, `smolagents` viene al rescate! Adopta el estándar [OpenTelemetry](https://opentelemetry.io/) para instrumentar ejecuciones de agentes, permitiendo una inspección y registro sin problemas. Con la ayuda de [Langfuse](https://langfuse.com/) y el `SmolagentsInstrumentor`, Alfred puede rastrear y analizar fácilmente el comportamiento de su agente. ¡Configurarlo es sencillo! Primero, necesitamos instalar las dependencias necesarias: ```bash pip install opentelemetry-sdk opentelemetry-exporter-otlp openinference-instrumentation-smolagents ``` A continuación, Alfred ya ha creado una cuenta en Langfuse y tiene sus claves API listas. Si aún no lo has hecho, puedes registrarte en Langfuse Cloud [aquí](https://cloud.langfuse.com/) o explorar [alternativas](https://huggingface.co/docs/smolagents/tutorials/inspect_runs). Una vez que tengas tus claves API, deben configurarse correctamente de la siguiente manera: ```python import os import base64 LANGFUSE_PUBLIC_KEY="pk-lf-..." LANGFUSE_SECRET_KEY="sk-lf-..." LANGFUSE_AUTH=base64.b64encode(f"{LANGFUSE_PUBLIC_KEY}:{LANGFUSE_SECRET_KEY}".encode()).decode() os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = "https://cloud.langfuse.com/api/public/otel" # Región de datos EU # os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = "https://us.cloud.langfuse.com/api/public/otel" # Región de datos US os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = f"Authorization=Basic {LANGFUSE_AUTH}" ``` Finalmente, Alfred está listo para inicializar el `SmolagentsInstrumentor` y comenzar a rastrear el rendimiento de su agente. ```python from opentelemetry.sdk.trace import TracerProvider from openinference.instrumentation.smolagents import SmolagentsInstrumentor from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter from opentelemetry.sdk.trace.export import SimpleSpanProcessor trace_provider = TracerProvider() trace_provider.add_span_processor(SimpleSpanProcessor(OTLPSpanExporter())) SmolagentsInstrumentor().instrument(tracer_provider=trace_provider) ``` ¡Alfred ahora está conectado 🔌! Las ejecuciones de `smolagents` se están registrando en Langfuse, dándole visibilidad completa del comportamiento del agente. Con esta configuración, está listo para revisar ejecuciones anteriores y refinar aún más su Agente Preparador de Fiestas. ```python from smolagents import CodeAgent, InferenceClientModel agent = CodeAgent(tools=[], model=InferenceClientModel()) alfred_agent = agent.from_hub('sergiopaniego/AlfredAgent', trust_remote_code=True) alfred_agent.run("Dame la mejor lista de reproducción para una fiesta en la mansión de Wayne. La idea de la fiesta es un tema de 'mascarada de villanos'") ``` Alfred ahora puede acceder a estos registros [aquí](https://cloud.langfuse.com/project/cm7bq0abj025rad078ak3luwi/traces/995fc019255528e4f48cf6770b0ce27b?timestamp=2025-02-19T10%3A28%3A36.929Z) para revisarlos y analizarlos. Mientras tanto, la [lista de reproducción sugerida](https://open.spotify.com/playlist/0gZMMHjuxMrrybQ7wTMTpw) establece el ambiente perfecto para los preparativos de la fiesta. ¿Genial, verdad? 🎶 --- Ahora que hemos creado nuestro primer Agente de Código, **aprendamos cómo podemos crear Agentes de Llamada a Herramientas**, el segundo tipo de agente disponible en `smolagents`. ## Recursos - [Blog de smolagents](https://huggingface.co/blog/smolagents) - Introducción a smolagents e interacciones de código - [smolagents: Construyendo Buenos Agentes](https://huggingface.co/docs/smolagents/tutorials/building_good_agents) - Mejores prácticas para agentes confiables - [Construyendo Agentes Efectivos - Anthropic](https://www.anthropic.com/research/building-effective-agents) - Principios de diseño de agentes - [Compartiendo ejecuciones con OpenTelemetry](https://huggingface.co/docs/smolagents/tutorials/inspect_runs) - Detalles sobre cómo configurar OpenTelemetry para rastrear tus agentes. ================================================ FILE: units/es/unit2/smolagents/conclusion.mdx ================================================ # Conclusión ¡Felicitaciones por terminar el módulo de `smolagents` de esta segunda Unidad 🥳 ¡Acabas de dominar los fundamentos de `smolagents` y has construido tu propio Agente! Ahora que tienes habilidades en `smolagents`, puedes comenzar a crear Agentes que resolverán tareas que te interesen. En el próximo módulo, vas a aprender **cómo construir Agentes con LlamaIndex**. Finalmente, nos encantaría **escuchar lo que piensas del curso y cómo podemos mejorarlo**. Si tienes algún comentario, por favor 👉 [completa este formulario](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ### Sigue aprendiendo, mantente increíble 🤗 ================================================ FILE: units/es/unit2/smolagents/final_quiz.mdx ================================================ # ¡Hora del Examen! ¡Buen trabajo al estudiar el material sobre `smolagents`! Ya has logrado mucho. Ahora, es momento de poner a prueba tus conocimientos con un cuestionario. 🧠 ## Instrucciones - El cuestionario consiste en preguntas de código. - Se te darán instrucciones para completar fragmentos de código. - Lee las instrucciones cuidadosamente y completa los fragmentos de código según corresponda. - Para cada pregunta, recibirás el resultado y algunos comentarios. 🧘 **Este cuestionario no está calificado ni certificado**. Se trata de que comprendas la biblioteca `smolagents` y sepas si deberías dedicar más tiempo al material escrito. En las próximas unidades pondrás este conocimiento a prueba en casos de uso y proyectos. ¡Comencemos! ## Cuestionario 🚀 También puedes acceder al cuestionario 👉 [aquí](https://huggingface.co/spaces/agents-course/unit2_smolagents_quiz) ================================================ FILE: units/es/unit2/smolagents/introduction.mdx ================================================ # Introducción a `smolagents` Miniatura de la Unidad 2.1 Bienvenido/a a este módulo, donde aprenderás **cómo construir agentes efectivos** usando la librería [`smolagents`](https://github.com/huggingface/smolagents), que proporciona un marco ligero para crear agentes de IA capaces. `smolagents` es una librería de Hugging Face; por lo tanto, agradeceríamos tu apoyo **marcando con una estrella** el [`repositorio`](https://github.com/huggingface/smolagents) de smolagents: marcando con estrella smolagents ## Descripción General del Módulo Este módulo proporciona una visión completa de conceptos clave y estrategias prácticas para construir agentes inteligentes usando `smolagents`. Con tantos frameworks de código abierto disponibles, es esencial entender los componentes y capacidades que hacen de `smolagents` una opción útil o determinar cuándo otra solución podría ser más adecuada. Exploraremos tipos de agentes críticos, incluyendo agentes de código diseñados para tareas de desarrollo de software, agentes de llamada a herramientas para crear flujos de trabajo modulares basados en funciones, y agentes de recuperación que acceden y sintetizan información. Además, cubriremos la orquestación de múltiples agentes asi como la integración de capacidades de visión y navegación web, que desbloquean nuevas posibilidades para aplicaciones dinámicas y conscientes del contexto. En esta unidad, Alfred, el agente de la Unidad 1, hace su regreso. Esta vez, está usando el framework `smolagents` para su funcionamiento interno. Juntos, exploraremos los conceptos clave detrás de este framework mientras Alfred aborda varias tareas. Alfred está organizando una fiesta en la Mansión Wayne mientras la familia Wayne 🦇 está fuera, y tiene mucho que hacer. ¡Únete a nosotros mientras mostramos su recorrido y como maneja estas tareas con `smolagents`! > [!TIP] > En esta unidad, aprenderás a construir agentes de IA con la librería `smolagents`. Tus agentes podrán buscar datos, ejecutar código e interactuar con páginas web. También aprenderás como combinar múltiples agentes para crear sistemas más potentes. ![Alfred el agente](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit1/this-is-alfred.jpg) ## Contenidos Durante esta unidad sobre `smolagents`, cubrimos: ### 1️⃣ [Por qué usar smolagents](./why_use_smolagents) `smolagents` es uno de los muchos frameworks de agentes de código abierto disponibles para el desarrollo de aplicaciones. Las opciones alternativas incluyen `LlamaIndex` y `LangGraph`, que también se cubren en otros módulos de este curso. `smolagents` ofrece varias características clave que podrían hacerlo una gran opción para casos de uso específicos, pero siempre debemos considerar todas las opciones al seleccionar un framework. Exploraremos las ventajas y desventajas de usar `smolagents`, ayudándote a tomar una decisión informada basada en los requisitos de tu proyecto. ### 2️⃣ [Agentes de Código](./code_agents) Los `CodeAgents` (Agentes de Código) son el tipo principal de agente en `smolagents`. En lugar de generar JSON o texto, estos agentes producen código Python para realizar acciones. Este módulo explora su propósito, funcionalidad y cómo funcionan, junto con ejemplos prácticos para mostrar sus capacidades. ### 3️⃣ [Agentes de Llamada a Herramientas](./tool_calling_agents) Los `ToolCallingAgents` (Agentes de Llamada a Herramientas) son el segundo tipo de agente soportado por `smolagents`. A diferencia de los `CodeAgents`, que generan código Python, estos agentes dependen de bloques JSON/texto que el sistema debe analizar e interpretar para ejecutar acciones. Este módulo cubre su funcionalidad, sus diferencias clave con los `CodeAgents`, y proporciona un ejemplo para ilustrar su uso. ### 4️⃣ [Herramientas](./tools) Como vimos en la Unidad 1, las herramientas son funciones que un LLM puede usar dentro de un sistema de agentes, y actúan como los bloques de construcción esenciales para el comportamiento del agente. Este módulo cubre cómo crear herramientas, su estructura y diferentes métodos de implementación usando la clase `Tool` o el decorador `@tool`. También aprenderás sobre la caja de herramientas predeterminada, cómo compartir herramientas con la comunidad y cómo cargar herramientas contribuidas por la comunidad para usarlas en tus agentes. ### 5️⃣ [Agentes de Recuperación](./retrieval_agents) Los agentes de recuperación permiten a los modelos acceder a bases de conocimiento, haciendo posible buscar, sintetizar y recuperar información de múltiples fuentes. Aprovechan los almacenes vectoriales para una recuperación eficiente e implementan patrones de **Generación Aumentada por Recuperación (RAG)**. Estos agentes son particularmente útiles para integrar la búsqueda web con bases de conocimiento personalizadas mientras mantienen el contexto de la conversación a través de sistemas de memoria. Este módulo explora estrategias de implementación, incluyendo mecanismos de respaldo para una recuperación de información robusta. ### 6️⃣ [Sistemas Multi-Agente](./multi_agent_systems) Orquestar múltiples agentes de manera efectiva es crucial para construir sistemas multi-agente potentes. Al combinar agentes con diferentes capacidades—como un agente de búsqueda web con un agente de ejecución de código—puedes crear soluciones más sofisticadas. Este módulo se enfoca en diseñar, implementar y gestionar sistemas multi-agente para maximizar la eficiencia y fiabilidad. ### 7️⃣ [Agentes de Visión y Navegador](./vision_agents) Los agentes de visión extienden las capacidades tradicionales de los agentes al incorporar **Modelos de Visión-Lenguaje (VLMs)**, permitiéndoles procesar e interpretar información visual. Este módulo explora cómo diseñar e integrar agentes potenciados por VLM, desbloqueando funcionalidades avanzadas como razonamiento basado en imágenes, análisis de datos visuales e interacciones multimodales. También usaremos agentes de visión para construir un agente de navegador que pueda navegar por la web y extraer información de ella. ## Recursos - [Documentación de smolagents](https://huggingface.co/docs/smolagents) - Documentación oficial de la biblioteca smolagents - [Construyendo Agentes Efectivos](https://www.anthropic.com/research/building-effective-agents) - Artículo de investigación sobre arquitecturas de agentes - [Directrices para Agentes](https://huggingface.co/docs/smolagents/tutorials/building_good_agents) - Mejores prácticas para construir agentes confiables - [Agentes LangGraph](https://langchain-ai.github.io/langgraph/) - Ejemplos adicionales de implementaciones de agentes - [Guía de Llamada a Funciones](https://platform.openai.com/docs/guides/function-calling) - Entendiendo la llamada a funciones en LLMs - [Mejores Prácticas de RAG](https://www.pinecone.io/learn/retrieval-augmented-generation/) - Guía para implementar RAG de manera efectiva ================================================ FILE: units/es/unit2/smolagents/multi_agent_systems.mdx ================================================ # Sistemas Multi-Agente Los sistemas multi-agente permiten que **agentes especializados colaboren en tareas complejas**, mejorando la modularidad, escalabilidad y robustez. En lugar de depender de un solo agente, las tareas se distribuyen entre agentes con capacidades distintas. En **smolagents**, diferentes agentes pueden combinarse para generar código Python, llamar a herramientas externas, realizar búsquedas web y más. Al orquestar estos agentes, podemos crear flujos de trabajo potentes. Una configuración típica podría incluir: - Un **Agente Gestor** para la delegación de tareas - Un **Agente Intérprete de Código** para la ejecución de código - Un **Agente de Búsqueda Web** para la recuperación de información El diagrama a continuación ilustra una arquitectura multi-agente simple donde un **Agente Gestor** coordina una **Herramienta Intérprete de Código** y un **Agente de Búsqueda Web**, que a su vez utiliza herramientas como `DuckDuckGoSearchTool` y `VisitWebpageTool` para recopilar información relevante. ## Sistemas Multi-Agente en Acción Un sistema multi-agente consiste en múltiples agentes especializados trabajando juntos bajo la coordinación de un **Agente Orquestador**. Este enfoque permite flujos de trabajo complejos distribuyendo tareas entre agentes con roles distintos. Por ejemplo, un **sistema RAG Multi-Agente** puede integrar: - Un **Agente Web** para navegar por internet. - Un **Agente Recuperador** para obtener información de bases de conocimiento. - Un **Agente de Generación de Imágenes** para producir elementos visuales. Todos estos agentes operan bajo un orquestador que gestiona la delegación de tareas y la interacción. ## Resolviendo una tarea compleja con una jerarquía multi-agente > [!TIP] > Puedes seguir el código en este notebook que puedes ejecutar usando Google Colab. ¡La recepción se acerca! Con tu ayuda, Alfred ya casi ha terminado con los preparativos. Pero ahora hay un problema: el Batmóvil ha desaparecido. Alfred necesita encontrar un reemplazo, y encontrarlo rápidamente. Afortunadamente, se han realizado algunas biografías cinematográficas sobre la vida de Bruce Wayne, así que tal vez Alfred podría conseguir un automóvil abandonado en uno de los sets de filmación y rediseñarlo según los estándares modernos, lo que ciertamente incluiría una opción de conducción autónoma completa. Pero esto podría estar en cualquier lugar de las locaciones de filmación alrededor del mundo, que podrían ser numerosas. Así que Alfred quiere tu ayuda. ¿Podrías construir un agente capaz de resolver esta tarea? > 👉 Encuentra todas las locaciones de filmación de Batman en el mundo, calcula el tiempo de transferencia en avión de carga hasta allí, y represéntalas en un mapa, con un color que varíe según el tiempo de transferencia en avión. También representa algunas fábricas de superdeportivos con el mismo tiempo de transferencia en avión. ¡Vamos a construir esto! Este ejemplo necesita algunos paquetes adicionales, así que vamos a instalarlos primero: ```bash pip install 'smolagents[litellm]' matplotlib geopandas shapely kaleido -q ``` ### Primero creamos una herramienta para obtener el tiempo de transferencia del avión de carga. ```python import math from typing import Optional, Tuple from smolagents import tool @tool def calculate_cargo_travel_time( origin_coords: Tuple[float, float], destination_coords: Tuple[float, float], cruising_speed_kmh: Optional[float] = 750.0, # Average speed for cargo planes ) -> float: """ Calculate the travel time for a cargo plane between two points on Earth using great-circle distance. Args: origin_coords: Tuple of (latitude, longitude) for the starting point destination_coords: Tuple of (latitude, longitude) for the destination cruising_speed_kmh: Optional cruising speed in km/h (defaults to 750 km/h for typical cargo planes) Returns: float: The estimated travel time in hours Example: >>> # Chicago (41.8781° N, 87.6298° W) to Sydney (33.8688° S, 151.2093° E) >>> result = calculate_cargo_travel_time((41.8781, -87.6298), (-33.8688, 151.2093)) """ def to_radians(degrees: float) -> float: return degrees * (math.pi / 180) # Extract coordinates lat1, lon1 = map(to_radians, origin_coords) lat2, lon2 = map(to_radians, destination_coords) # Earth's radius in kilometers EARTH_RADIUS_KM = 6371.0 # Calculate great-circle distance using the haversine formula dlon = lon2 - lon1 dlat = lat2 - lat1 a = ( math.sin(dlat / 2) ** 2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2) ** 2 ) c = 2 * math.asin(math.sqrt(a)) distance = EARTH_RADIUS_KM * c # Add 10% to account for non-direct routes and air traffic controls actual_distance = distance * 1.1 # Calculate flight time # Add 1 hour for takeoff and landing procedures flight_time = (actual_distance / cruising_speed_kmh) + 1.0 # Format the results return round(flight_time, 2) print(calculate_cargo_travel_time((41.8781, -87.6298), (-33.8688, 151.2093))) ``` ### Configurando el agente Para el proveedor de modelos, usamos Together AI, ¡uno de los nuevos [proveedores de inferencia en el Hub](https://huggingface.co/blog/inference-providers)! La herramienta GoogleSearchTool usa la [API de Serper](https://serper.dev) para buscar en la web, por lo que requiere haber configurado la variable de entorno `SERPAPI_API_KEY` y pasar `provider="serpapi"` o tener `SERPER_API_KEY` y pasar `provider=serper`. Si no tienes ningún proveedor de Serp API configurado, puedes usar `DuckDuckGoSearchTool` pero ten en cuenta que tiene un límite de tasa. ```python import os from PIL import Image from smolagents import CodeAgent, GoogleSearchTool, InferenceClientModel, VisitWebpageTool model = InferenceClientModel(model_id="Qwen/Qwen2.5-Coder-32B-Instruct", provider="together") ``` Podemos empezar creando un agente simple como base para darnos un informe simple. ```python task = """Encuentra todas las locaciones de filmación de Batman en el mundo, calcula el tiempo de transferencia en avión de carga hasta aquí (estamos en Gotham, 40.7128° N, 74.0060° W), y devuélvelas a mí como un dataframe de pandas. También dame algunas fábricas de superdeportivos con el mismo tiempo de transferencia en avión.""" ``` ```python agent = CodeAgent( model=model, tools=[GoogleSearchTool("serper"), VisitWebpageTool(), calculate_cargo_travel_time], additional_authorized_imports=["pandas"], max_steps=20, ) ``` ```python result = agent.run(task) ``` ```python result ``` En nuestro caso, genera este output: ```python | | Location | Travel Time to Gotham (hours) | |--|------------------------------------------------------|------------------------------| | 0 | Necropolis Cemetery, Glasgow, Scotland, UK | 8.60 | | 1 | St. George's Hall, Liverpool, England, UK | 8.81 | | 2 | Two Temple Place, London, England, UK | 9.17 | | 3 | Wollaton Hall, Nottingham, England, UK | 9.00 | | 4 | Knebworth House, Knebworth, Hertfordshire, UK | 9.15 | | 5 | Acton Lane Power Station, Acton Lane, Acton, UK | 9.16 | | 6 | Queensboro Bridge, New York City, USA | 1.01 | | 7 | Wall Street, New York City, USA | 1.00 | | 8 | Mehrangarh Fort, Jodhpur, Rajasthan, India | 18.34 | | 9 | Turda Gorge, Turda, Romania | 11.89 | | 10 | Chicago, USA | 2.68 | | 11 | Hong Kong, China | 19.99 | | 12 | Cardington Studios, Northamptonshire, UK | 9.10 | | 13 | Warner Bros. Leavesden Studios, Hertfordshire, UK | 9.13 | | 14 | Westwood, Los Angeles, CA, USA | 6.79 | | 15 | Woking, UK (McLaren) | 9.13 | ``` Podríamos mejorar esto un poco agregando algunos pasos de planificación y más instrucciones. Los pasos de planificación permiten al agente pensar con anticipación y planificar sus próximos pasos, lo que puede ser útil para tareas más complejas. ```python agent.planning_interval = 4 detailed_report = agent.run(f""" Eres un analista experto. Creas informes exhaustivos después de visitar muchos sitios web. No dudes en buscar muchas consultas a la vez en un bucle for. Para cada dato que encuentres, visita la URL de origen para confirmar los números. {task} """) print(detailed_report) ``` ```python detailed_report ``` En nuestro caso, genera este output: ```python | | Location | Travel Time (hours) | |--|--------------------------------------------------|---------------------| | 0 | Bridge of Sighs, Glasgow Necropolis, Glasgow, UK | 8.6 | | 1 | Wishart Street, Glasgow, Scotland, UK | 8.6 | ``` Gracias a estos cambios rápidos, obtuvimos un informe mucho más conciso proporcionando simplemente una instrucción detallada a nuestro agente y dándole capacidades de planificación. El contexto de la ventana del modelo se está llenando rápidamente. Así que **si le pedimos a nuestro agente que combine los resultados de una búsqueda detallada con otra, será más lento y rápidamente aumentará los tokens y los costos**. ➡️ Necesitamos mejorar la estructura de nuestro sistema. ### ✌️ Dividiendo la tarea entre dos agentes Las estructuras multi-agente permiten separar memorias entre diferentes sub-tareas, con dos grandes beneficios: - Cada agente está más enfocado en su tarea principal, por lo que es más performante - Separar memorias reduce la cantidad de tokens de entrada en cada paso, reduciendo la latencia y el costo. Vamos a crear un equipo con un agente de búsqueda web dedicado, gestionado por otro agente. El agente gestor debe tener capacidades de trazado para escribir su informe final: así que vamos a darle acceso a importaciones adicionales, incluyendo `matplotlib`, y `geopandas` + `shapely` para trazado espacial. ```python model = InferenceClientModel( "Qwen/Qwen2.5-Coder-32B-Instruct", provider="together", max_tokens=8096 ) web_agent = CodeAgent( model=model, tools=[ GoogleSearchTool(provider="serper"), VisitWebpageTool(), calculate_cargo_travel_time, ], name="web_agent", description="Navega por la web para encontrar información", verbosity_level=0, max_steps=10, ) ``` El agente gestor necesitará hacer algo de trabajo mental pesado. Así que le damos el modelo más fuerte [DeepSeek-R1](https://huggingface.co/deepseek-ai/DeepSeek-R1), y agregamos un `planning_interval` a la mezcla. ```python from smolagents.utils import encode_image_base64, make_image_url from smolagents import OpenAIServerModel def check_reasoning_and_plot(final_answer, agent_memory): final_answer multimodal_model = OpenAIServerModel("gpt-4o", max_tokens=8096) filepath = "saved_map.png" assert os.path.exists(filepath), "Asegúrate de guardar el trazado bajo saved_map.png!" image = Image.open(filepath) prompt = ( f"Aquí está una tarea dada por el usuario y los pasos del agente: {agent_memory.get_succinct_steps()}. Ahora aquí está el trazado que se hizo." "Por favor, verifica que el proceso de razonamiento y el trazado sean correctos: ¿responden correctamente a la tarea dada?" "Primero enumera razones por las que sí/no, luego escribe tu decisión final: PASS en mayúsculas si es satisfactorio, FAIL si no lo es." "No seas duro: si el trazado resuelve en gran medida la tarea, debe pasar." "Para pasar, un trazado debe hacerse usando px.scatter_map y no cualquier otro método (scatter_map se ve mejor)." ) messages = [ { "role": "user", "content": [ { "type": "text", "text": prompt, }, { "type": "image_url", "image_url": {"url": make_image_url(encode_image_base64(image))}, }, ], } ] output = multimodal_model(messages).content print("Retroalimentación: ", output) if "FAIL" in output: raise Exception(output) return True manager_agent = CodeAgent( model=InferenceClientModel("deepseek-ai/DeepSeek-R1", provider="together", max_tokens=8096), tools=[calculate_cargo_travel_time], managed_agents=[web_agent], additional_authorized_imports=[ "geopandas", "plotly", "shapely", "json", "pandas", "numpy", ], planning_interval=5, verbosity_level=2, final_answer_checks=[check_reasoning_and_plot], max_steps=15, ) ``` Vamos a inspeccionar qué se ve este equipo: ```python manager_agent.visualize() ``` Esto generará algo como esto, ayudándonos a entender la estructura y la relación entre agentes y herramientas utilizadas: ```python CodeAgent | deepseek-ai/DeepSeek-R1 ├── ✅ Authorized imports: ['geopandas', 'plotly', 'shapely', 'json', 'pandas', 'numpy'] ├── 🛠️ Tools: │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ │ ┃ Name ┃ Description ┃ Arguments ┃ │ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ │ calculate_cargo_travel_time │ Calculate the travel time for a cargo │ origin_coords (`array`): Tuple of │ │ │ │ plane between two points on Earth │ (latitude, longitude) for the │ │ │ │ using great-circle distance. │ starting point │ │ │ │ │ destination_coords (`array`): Tuple │ │ │ │ │ of (latitude, longitude) for the │ │ │ │ │ destination │ │ │ │ │ cruising_speed_kmh (`number`): │ │ │ │ │ Optional cruising speed in km/h │ │ │ │ │ (defaults to 750 km/h for typical │ │ │ │ │ cargo planes) │ │ │ final_answer │ Provides a final answer to the given │ answer (`any`): The final answer to │ │ │ │ problem. │ the problem │ │ └─────────────────────────────┴───────────────────────────────────────┴───────────────────────────────────────┘ └── 🤖 Managed agents: └── web_agent | CodeAgent | Qwen/Qwen2.5-Coder-32B-Instruct ├── ✅ Authorizar imports: [] ├── 📝 Description: Navega por la web para encontrar información └── 🛠️ Tools: ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ Name ┃ Description ┃ Arguments ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ web_search │ Performs a google web search for │ query (`string`): The search │ │ │ your query then returns a string │ query to perform. │ │ │ of the top search results. │ filter_year (`integer`): │ │ │ │ Optionally restrict results to a │ │ │ │ certain year │ │ visit_webpage │ Visits a webpage at the given url │ url (`string`): The url of the │ │ │ and reads its content as a │ webpage to visit. │ │ │ markdown string. Use this to │ │ │ │ browse webpages. │ │ │ calculate_cargo_travel_time │ Calculate the travel time for a │ origin_coords (`array`): Tuple of │ │ │ cargo plane between two points on │ (latitude, longitude) for the │ │ │ Earth using great-circle │ starting point │ │ │ distance. │ destination_coords (`array`): │ │ │ │ Tuple of (latitude, longitude) │ │ │ │ for the destination │ │ │ │ cruising_speed_kmh (`number`): │ │ │ │ Optional cruising speed in km/h │ │ │ │ (defaults to 750 km/h for typical │ │ │ │ cargo planes) │ │ final_answer │ Provides a final answer to the │ answer (`any`): The final answer │ │ │ given problem. │ to the problem │ └─────────────────────────────┴───────────────────────────────────┴───────────────────────────────────┘ ``` ```python manager_agent.run(""" Encuentra todas las locaciones de filmación de Batman en el mundo, calcula el tiempo de transferencia en avión de carga hasta aquí (estamos en Gotham, 40.7128° N, 74.0060° W). También dame algunas fábricas de superdeportivos con el mismo tiempo de transferencia en avión. Necesito al menos 6 puntos en total. Representa esto como un mapa espacial del mundo, con las locaciones representadas como puntos de dispersión con un color que depende del tiempo de transferencia, y guárdalo en saved_map.png! Aquí hay un ejemplo de cómo trazar y devolver un mapa: import plotly.express as px df = px.data.carshare() fig = px.scatter_map(df, lat="centroid_lat", lon="centroid_lon", text="name", color="peak_hour", size=100, color_continuous_scale=px.colors.sequential.Magma, size_max=15, zoom=1) fig.show() fig.write_image("saved_image.png") final_answer(fig) Nunca intentes procesar cadenas usando código: cuando tengas una cadena para leer, simplemente imprímela y la verás. """) ``` No sé cómo salió en tu ejecución, pero en la mía, el agente gestor dividió hábilmente las tareas dadas al agente web en `1. Buscar locaciones de filmación de Batman`, luego `2. Encontrar fábricas de superdeportivos`, antes de agregar las listas y trazar el mapa. Vamos a ver qué se ve el mapa inspeccionándolo directamente desde el estado del agente: ```python manager_agent.python_executor.state["fig"] ``` Esto generará el mapa: ![Multiagent system example output map](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/smolagents/output_map.png) ## Recursos - [Sistemas Multi-Agente](https://huggingface.co/docs/smolagents/main/en/examples/multiagents) – Visión general de los sistemas multi-agente. - [¿Qué es Agentic RAG?](https://weaviate.io/blog/what-is-agentic-rag) – Introducción a Agentic RAG. - [Sistema RAG Multi-Agente 🤖🤝🤖 Receta](https://huggingface.co/learn/cookbook/multiagent_rag_system) – Guía paso a paso para construir un sistema RAG multi-agente. ================================================ FILE: units/es/unit2/smolagents/quiz1.mdx ================================================ # Pequeño Quiz (no calificado) [[quiz1]] ¡Vamos a poner a prueba tu comprensión de `smolagents` con un quiz rápido! Recuerda, ponerte a prueba ayuda a reforzar el aprendizaje e identificar áreas que pueden necesitar revisión. Este es un quiz opcional y no está calificado. ### P1: ¿Cuál es una de las principales ventajas de elegir `smolagents` sobre otros frameworks? ¿Qué afirmación captura mejor una fortaleza central del enfoque de `smolagents`? --- ### P2: ¿En qué escenario probablemente te beneficiarías más al usar smolagents? ¿Qué situación se alinea bien con lo que smolagents hace mejor? --- ### P3: smolagents ofrece flexibilidad en la integración de modelos. ¿Qué afirmación refleja mejor su enfoque? Elige la descripción más precisa de cómo smolagents interopera con LLMs. --- ### P4: ¿Cómo maneja smolagents el debate entre acciones basadas en código y acciones basadas en JSON? ¿Qué afirmación caracteriza correctamente la filosofía de smolagents sobre los formatos de acción? --- ### P5: ¿Cómo se integra smolagents con Hugging Face Hub para obtener beneficios adicionales? ¿Qué afirmación describe con precisión una de las ventajas principales de la integración con Hub? --- ¡Felicidades por completar este quiz! 🎉 Si te equivocaste en alguna pregunta, considera revisar la sección *Por qué usar smolagents* para una comprensión más profunda. Si te fue bien, ¡estás listo para explorar temas más avanzados en smolagents! ================================================ FILE: units/es/unit2/smolagents/quiz2.mdx ================================================ # Pequeño Quiz (no calificado) [[quiz2]] Es hora de poner a prueba tu comprensión de las secciones *Agentes de Código*, *Agentes de Llamada a Herramientas* y *Herramientas*. Este quiz es opcional y no está calificado. --- ### P1: ¿Cuál es la diferencia clave entre crear una herramienta con el decorador `@tool` versus crear una subclase de `Tool` en smolagents? ¿Qué afirmación describe mejor la distinción entre estos dos enfoques para definir herramientas? @tool es obligatorio para herramientas basadas en recuperación, mientras que las subclases de Tool son solo para tareas de generación de texto", explain: "Ambos enfoques pueden usarse para cualquier tipo de herramienta, incluidas las basadas en recuperación o generación de texto.", }, { text: "El decorador @tool se recomienda para herramientas simples basadas en funciones, mientras que las subclases de Tool ofrecen más flexibilidad para funcionalidades complejas o metadatos personalizados", explain: "Esto es correcto. El enfoque del decorador es más simple, pero la subclasificación permite un comportamiento más personalizado.", correct: true }, { text: "@tool solo puede usarse en sistemas multi-agente, mientras que crear una subclase de Tool es para escenarios de un solo agente", explain: "Todos los agentes (individuales o múltiples) pueden usar cualquiera de los enfoques para definir herramientas; no existe tal restricción.", }, { text: "Decorar una función con @tool reemplaza la necesidad de un docstring, mientras que las subclases no deben incluir docstrings", explain: "Ambos métodos se benefician de docstrings claros. El decorador no los reemplaza, y una subclase también puede tener docstrings.", } ]} /> --- ### P2: ¿Cómo maneja un CodeAgent tareas de múltiples pasos utilizando el enfoque ReAct (Reason + Act)? ¿Qué afirmación describe correctamente cómo el CodeAgent ejecuta una serie de pasos para resolver una tarea? --- ### P3: ¿Cuál de las siguientes es una ventaja principal de compartir una herramienta en Hugging Face Hub? Selecciona la mejor razón por la que un desarrollador podría subir y compartir su herramienta personalizada. --- ### P4: ToolCallingAgent difiere de CodeAgent en cómo ejecuta acciones. ¿Qué afirmación es correcta? Elige la opción que describe con precisión cómo funciona ToolCallingAgent. --- ### P5: ¿Qué se incluye en la caja de herramientas predeterminada de smolagents y por qué podrías usarla? ¿Qué afirmación captura mejor el propósito y el contenido de la caja de herramientas predeterminada en smolagents? --- ¡Felicidades por completar este quiz! 🎉 Si alguna pregunta te dio problemas, revisa las secciones *Agentes de Código*, *Agentes de Llamada a Herramientas* o *Herramientas* para fortalecer tu comprensión. Si lo has hecho bien, ¡estás en buen camino para construir aplicaciones robustas con smolagents! ================================================ FILE: units/es/unit2/smolagents/retrieval_agents.mdx ================================================ # Construyendo Sistemas RAG con Agentes > [!TIP] > Puedes seguir el código en este notebook que puedes ejecutar usando Google Colab. Los sistemas de Generación Aumentada por Recuperación (RAG) combinan las capacidades de recuperación de datos y modelos de generación para proporcionar respuestas contextualizadas. Por ejemplo, la consulta de un usuario se pasa a un motor de búsqueda, y los resultados recuperados se entregan al modelo junto con la consulta. El modelo luego genera una respuesta basada en la consulta y la información recuperada. El RAG con Agentes (Generación Aumentada por Recuperación) extiende los sistemas RAG tradicionales al **combinar agentes autónomos con recuperación dinámica de conocimiento**. Mientras que los sistemas RAG tradicionales utilizan un LLM para responder consultas basadas en datos recuperados, el RAG con agentes **permite un control inteligente tanto de los procesos de recuperación como de generación**, mejorando la eficiencia y precisión. Los sistemas RAG tradicionales enfrentan limitaciones clave, como **depender de un solo paso de recuperación** y enfocarse en la similitud semántica directa con la consulta del usuario, lo que puede pasar por alto información relevante. El RAG con agentes aborda estos problemas permitiendo que el agente formule autónomamente consultas de búsqueda, critique los resultados recuperados y realice múltiples pasos de recuperación para obtener un resultado más personalizado y completo. ## Recuperación Básica con DuckDuckGo Vamos a construir un agente simple que pueda buscar en la web usando DuckDuckGo. Este agente recuperará información y sintetizará respuestas para contestar consultas. Con RAG con agentes, el agente de Alfred puede: * Buscar las últimas tendencias en fiestas de superhéroes * Refinar resultados para incluir elementos de lujo * Sintetizar información en un plan completo Así es como el agente de Alfred puede lograr esto: ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel # Initialize the search tool search_tool = DuckDuckGoSearchTool() # Initialize the model model = InferenceClientModel() agent = CodeAgent( model=model, tools=[search_tool] ) # Example usage response = agent.run( "Buscar ideas de fiesta temática de superhéroes de lujo, incluyendo decoración, entretenimiento y catering." ) print(response) ``` El agente sigue este proceso: 1. **Analiza la Solicitud:** El agente de Alfred identifica los elementos clave de la consulta—planificación de fiesta temática de superhéroes de lujo, con enfoque en decoración, entretenimiento y catering. 2. **Realiza la Recuperación:** El agente utiliza DuckDuckGo para buscar la información más relevante y actualizada, asegurándose de que se alinee con las preferencias refinadas de Alfred para un evento lujoso. 3. **Sintetiza la Información:** Después de recopilar los resultados, el agente los procesa en un plan coherente y accionable para Alfred, cubriendo todos los aspectos de la fiesta. 4. **Almacena para Referencia Futura:** El agente almacena la información recuperada para un fácil acceso al planificar eventos futuros, optimizando la eficiencia en tareas posteriores. ## Herramienta de Base de Conocimiento Personalizada Para tareas especializadas, una base de conocimiento personalizada puede ser invaluable. Vamos a crear una herramienta que consulte una base de datos vectorial de documentación técnica o conocimiento especializado. Utilizando búsqueda semántica, el agente puede encontrar la información más relevante para las necesidades de Alfred. Una base de datos vectorial es simplemente una colección de documentos con representaciones enriquecidas por modelos de ML especializados, que permiten la búsqueda y recuperación rápida de los documentos. Este enfoque combina conocimiento predefinido con búsqueda semántica para proporcionar soluciones contextualizadas para la planificación de eventos. Con acceso a conocimiento especializado, Alfred puede perfeccionar cada detalle de la fiesta. En este ejemplo, crearemos una herramienta que recupera ideas de planificación de fiestas desde una base de conocimiento personalizada. Usaremos un recuperador BM25 para buscar en la base de conocimiento y devolver los mejores resultados, y `RecursiveCharacterTextSplitter` para dividir los documentos en fragmentos más pequeños para una búsqueda más eficiente. ```python from langchain.docstore.document import Document from langchain.text_splitter import RecursiveCharacterTextSplitter from smolagents import Tool from langchain_community.retrievers import BM25Retriever from smolagents import CodeAgent, InferenceClientModel class PartyPlanningRetrieverTool(Tool): name = "party_planning_retriever" description = "Utiliza búsqueda semántica para recuperar ideas de planificación de fiestas relevantes para la fiesta temática de superhéroes de Alfred en Wayne Manor." inputs = { "query": { "type": "string", "description": "La consulta a realizar. Esta debe ser una consulta relacionada con la planificación de fiestas o temas de superhéroes.", } } output_type = "string" def __init__(self, docs, **kwargs): super().__init__(**kwargs) self.retriever = BM25Retriever.from_documents( docs, k=5 # Retrieve the top 5 documents ) def forward(self, query: str) -> str: assert isinstance(query, str), "Tu consulta de búsqueda debe ser una cadena" docs = self.retriever.invoke( query, ) return "\nIdeas recuperadas:\n" + "".join( [ f"\n\n===== Idea {str(i)} =====\n" + doc.page_content for i, doc in enumerate(docs) ] ) # Simulate a knowledge base about party planning party_ideas = [ {"text": "Una fiesta de disfraces temática de superhéroes con decoración de lujo, incluyendo detalles dorados y cortinas de terciopelo.", "source": "Ideas de fiesta 1"}, {"text": "Contrata a un DJ profesional que pueda tocar música temática para superhéroes como Batman y Wonder Woman.", "source": "Ideas de entretenimiento"}, {"text": "Para el catering, sirve platos con nombres de superhéroes, como 'El smoothie verde de Hulk' y 'El filete de poder de Iron Man'.", "source": "Ideas de catering"}, {"text": "Decora con logotipos icónicos de superhéroes y proyecciones de Gotham y otras ciudades de superhéroes alrededor del lugar.", "source": "Ideas de decoración"}, {"text": "Experiencias interactivas con realidad virtual donde los invitados pueden participar en simulaciones de superhéroes o competir en juegos temáticos.", "source": "Ideas de entretenimiento"} ] source_docs = [ Document(page_content=doc["text"], metadata={"source": doc["source"]}) for doc in party_ideas ] # Split the documents into smaller chunks for more efficient search text_splitter = RecursiveCharacterTextSplitter( chunk_size=500, chunk_overlap=50, add_start_index=True, strip_whitespace=True, separators=["\n\n", "\n", ".", " ", ""], ) docs_processed = text_splitter.split_documents(source_docs) # Create the retriever tool party_planning_retriever = PartyPlanningRetrieverTool(docs_processed) # Initialize the agent agent = CodeAgent(tools=[party_planning_retriever], model=InferenceClientModel()) # Example usage response = agent.run( "Encuentra ideas para una fiesta temática de superhéroes de lujo, incluyendo entretenimiento, catering y opciones de decoración." ) print(response) ``` Este agente mejorado puede: 1. Primero verificar la documentación para obtener información relevante 2. Combinar ideas de la base de conocimiento 3. Mantener el contexto de la conversación en memoria ## Capacidades de Recuperación Mejoradas Al construir sistemas RAG con agentes, el agente puede emplear estrategias sofisticadas como: 1. **Reformulación de Consultas:** En lugar de usar la consulta del usuario en bruto, el agente puede elaborar términos de búsqueda optimizados que coincidan mejor con los documentos objetivo 2. **Recuperación Multi-Paso:** El agente puede realizar múltiples búsquedas, utilizando los resultados iniciales para informar consultas posteriores 3. **Integración de Fuentes:** La información puede combinarse de múltiples fuentes como búsqueda web y documentación local 4. **Validación de Resultados:** El contenido recuperado puede analizarse para determinar su relevancia y precisión antes de incluirlo en las respuestas Los sistemas RAG con agentes efectivos requieren una consideración cuidadosa de varios aspectos clave. El agente **debe seleccionar entre las herramientas disponibles según el tipo de consulta y el contexto**. Los sistemas de memoria ayudan a mantener el historial de conversación y evitar recuperaciones repetitivas. Tener estrategias de respaldo garantiza que el sistema pueda seguir proporcionando valor incluso cuando los métodos de recuperación principales fallan. Además, implementar pasos de validación ayuda a garantizar la precisión y relevancia de la información recuperada. ## Recursos - [RAG con Agentes: ¡potencia tu RAG con reformulación de consultas y auto-consulta! 🚀](https://huggingface.co/learn/cookbook/agent_rag) - Receta para desarrollar un sistema RAG con Agentes utilizando smolagents. ================================================ FILE: units/es/unit2/smolagents/tool_calling_agents.mdx ================================================ # Escribiendo acciones como fragmentos de código o estructuras JSON > [!TIP] > Puedes seguir el código en este notebook que puedes ejecutar usando Google Colab. Los Agentes de Llamada a Herramientas son el segundo tipo de agente disponible en `smolagents`. A diferencia de los Agentes de Código que utilizan fragmentos de Python, estos agentes **utilizan las capacidades integradas de llamada a herramientas de los proveedores de LLM** para generar llamadas a herramientas como **estructuras JSON**. Este es el enfoque estándar utilizado por OpenAI, Anthropic y muchos otros proveedores. Veamos un ejemplo. Cuando Alfred quiere buscar servicios de catering e ideas para fiestas, un `CodeAgent` generaría y ejecutaría código Python como este: ```python for query in [ "Mejores servicios de catering en Ciudad Gótica", "Ideas de temas de fiesta para superhéroes" ]: print(web_search(f"Buscar: {query}")) ``` Un `ToolCallingAgent` en cambio crearía una estructura JSON: ```python [ {"name": "web_search", "arguments": "Mejores servicios de catering en Ciudad Gótica"}, {"name": "web_search", "arguments": "Ideas de temas de fiesta para superhéroes"} ] ``` Esta estructura JSON se utiliza luego para ejecutar las llamadas a herramientas. Aunque `smolagents` se centra principalmente en `CodeAgents` ya que [tienen un mejor rendimiento general](https://huggingface.co/papers/2402.01030), los `ToolCallingAgents` pueden ser efectivos para sistemas simples que no requieren manejo de variables o llamadas a herramientas complejas. ![Acciones de Código vs JSON](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/code_vs_json_actions.png) ## ¿Cómo Funcionan los Agentes de Llamada a Herramientas? Los Agentes de Llamada a Herramientas siguen el mismo flujo de trabajo de múltiples pasos que los Agentes de Código (consulta la [sección anterior](./code_agents) para más detalles). La diferencia clave está en **cómo estructuran sus acciones**: en lugar de código ejecutable, **generan objetos JSON que especifican nombres de herramientas y argumentos**. El sistema luego **analiza estas instrucciones** para ejecutar las herramientas apropiadas. ## Ejemplo: Ejecutando un Agente de Llamada a Herramientas Revisemos el ejemplo anterior donde Alfred comenzó los preparativos de la fiesta, pero esta vez usaremos un `ToolCallingAgent` para destacar la diferencia. Construiremos un agente que pueda buscar en la web usando DuckDuckGo, al igual que en nuestro ejemplo de Agente de Código. La única diferencia es el tipo de agente - el framework se encarga de todo lo demás: ```python from smolagents import ToolCallingAgent, DuckDuckGoSearchTool, InferenceClientModel agent = ToolCallingAgent(tools=[DuckDuckGoSearchTool()], model=InferenceClientModel()) agent.run("Busca las mejores recomendaciones de música para una fiesta en la mansión Wayne.") ``` Cuando examines el rastro del agente, en lugar de ver `Executing parsed code:`, verás algo como: ```text ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ Llamando a herramienta: 'web_search' con argumentos: {'query': "mejores recomendaciones de música para una │ │ fiesta en la mansión Wayne"} │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ``` El agente genera una llamada a herramienta estructurada que el sistema procesa para producir la salida, en lugar de ejecutar directamente código como un `CodeAgent`. Ahora que entendemos ambos tipos de agentes, podemos elegir el adecuado para nuestras necesidades. ¡Continuemos explorando `smolagents` para hacer que la fiesta de Alfred sea un éxito! 🎉 ## Recursos - [Documentación de ToolCallingAgent](https://huggingface.co/docs/smolagents/v1.8.1/en/reference/agents#smolagents.ToolCallingAgent) - Documentación oficial para ToolCallingAgent ================================================ FILE: units/es/unit2/smolagents/tools.mdx ================================================ # Herramientas Como exploramos en la [unidad 1](https://huggingface.co/learn/agents-course/unit1/tools), los agentes utilizan herramientas para realizar diversas acciones. En `smolagents`, las herramientas son tratadas como **funciones que un LLM puede llamar dentro de un sistema de agentes**. Para interactuar con una herramienta, el LLM necesita una **descripción de la interfaz** con estos componentes clave: - **Nombre**: Cómo se llama la herramienta - **Descripción de la herramienta**: Qué hace la herramienta - **Tipos de entrada y descripciones**: Qué argumentos acepta la herramienta - **Tipo de salida**: Qué devuelve la herramienta Por ejemplo, mientras prepara una fiesta en la Mansión Wayne, Alfred necesita varias herramientas para recopilar información - desde buscar servicios de catering hasta encontrar ideas para temas de fiesta. Así es como podría verse la interfaz de una herramienta de búsqueda simple: - **Nombre:** `web_search` - **Descripción de la herramienta:** Busca en la web consultas específicas - **Entrada:** `query` (cadena) - El término de búsqueda a consultar - **Salida:** Cadena que contiene los resultados de la búsqueda Al utilizar estas herramientas, Alfred puede tomar decisiones informadas y recopilar toda la información necesaria para planificar la fiesta perfecta. A continuación, puedes ver una animación que ilustra cómo se gestiona una llamada a una herramienta: ![Pipeline de agente de https://huggingface.co/docs/smolagents/conceptual_guides/react](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/Agent_ManimCE.gif) ## Métodos de Creación de Herramientas En `smolagents`, las herramientas pueden definirse de dos maneras: 1. **Usando el decorador `@tool`** para herramientas simples basadas en funciones 2. **Creando una subclase de `Tool`** para funcionalidades más complejas ### El Decorador `@tool` El decorador `@tool` es **la forma recomendada para definir herramientas simples**. Internamente, smolagents analizará la información básica sobre la función desde Python. Por lo tanto, si nombras tu función claramente y escribes un buen docstring, será más fácil para el LLM utilizarla. Usando este enfoque, definimos una función con: - **Un nombre de función claro y descriptivo** que ayuda al LLM a entender su propósito. - **Anotaciones de tipo tanto para entradas como para salidas** para garantizar un uso adecuado. - **Una descripción detallada**, que incluye una sección `Args:` donde cada argumento se describe explícitamente. Estas descripciones proporcionan un contexto valioso para el LLM, por lo que es importante escribirlas cuidadosamente. #### Generando una herramienta que recupera el servicio de catering mejor valorado Alfred Catering > [!TIP] > Puedes seguir el código en este notebook que puedes ejecutar usando Google Colab. Imaginemos que Alfred ya ha decidido el menú para la fiesta, pero ahora necesita ayuda para preparar comida para un número tan grande de invitados. Para hacerlo, le gustaría contratar un servicio de catering y necesita identificar las opciones mejor valoradas disponibles. Alfred puede aprovechar una herramienta para buscar los mejores servicios de catering en su área. A continuación se muestra un ejemplo de cómo Alfred puede usar el decorador `@tool` para lograrlo: ```python from smolagents import CodeAgent, InferenceClientModel, tool # Imaginemos que tenemos una función que obtiene los servicios de catering mejor valorados. @tool def catering_service_tool(query: str) -> str: """ Esta herramienta devuelve el servicio de catering mejor valorado en Ciudad Gótica. Args: query: Un término de búsqueda para encontrar servicios de catering. """ # Lista de ejemplo de servicios de catering y sus calificaciones services = { "Gotham Catering Co.": 4.9, "Wayne Manor Catering": 4.8, "Gotham City Events": 4.7, } # Encuentra el servicio de catering mejor valorado (simulando el filtrado de consultas de búsqueda) best_service = max(services, key=services.get) return best_service agent = CodeAgent(tools=[catering_service_tool], model=InferenceClientModel()) # Ejecuta el agente para encontrar el mejor servicio de catering result = agent.run( "¿Puedes darme el nombre del servicio de catering mejor valorado en Ciudad Gótica?" ) print(result) # Salida: Gotham Catering Co. ``` ### Definiendo una Herramienta como una Clase de Python Este enfoque implica crear una subclase de [`Tool`](https://huggingface.co/docs/smolagents/v1.8.1/en/reference/tools#smolagents.Tool). Para herramientas complejas, podemos implementar una clase en lugar de una función de Python. La clase envuelve la función con metadatos que ayudan al LLM a entender cómo usarla de manera efectiva. En esta clase, definimos: - `name`: El nombre de la herramienta. - `description`: Una descripción utilizada para completar el prompt del sistema del agente. - `inputs`: Un diccionario con claves `type` y `description`, proporcionando información para ayudar al intérprete de Python a procesar las entradas. - `output_type`: Especifica el tipo de salida esperado. - `forward`: El método que contiene la lógica de inferencia a ejecutar. A continuación, podemos ver un ejemplo de una herramienta construida usando `Tool` y cómo integrarla dentro de un `CodeAgent`. #### Generando una herramienta para generar ideas sobre la fiesta temática de superhéroes La fiesta de Alfred en la mansión es un **evento temático de superhéroes**, pero necesita algunas ideas creativas para hacerla verdaderamente especial. Como anfitrión fantástico, quiere sorprender a los invitados con un tema único. Para hacer esto, puede usar un agente que genere ideas de fiestas temáticas de superhéroes basadas en una categoría dada. De esta manera, Alfred puede encontrar el tema de fiesta perfecto para impresionar a sus invitados. ```python from smolagents import Tool, CodeAgent, InferenceClientModel class SuperheroPartyThemeTool(Tool): name = "superhero_party_theme_generator" description = """ Esta herramienta sugiere ideas creativas para fiestas temáticas de superhéroes basadas en una categoría. Devuelve una idea única de tema para la fiesta.""" inputs = { "category": { "type": "string", "description": "El tipo de fiesta de superhéroes (por ejemplo, 'héroes clásicos', 'mascarada de villanos', 'Gotham futurista').", } } output_type = "string" def forward(self, category: str): themes = { "classic heroes": "Gala de la Liga de la Justicia: Los invitados vienen vestidos como sus héroes favoritos de DC con cócteles temáticos como 'El Ponche de Kryptonita'.", "villain masquerade": "Baile de los Pícaros de Gotham: Una mascarada misteriosa donde los invitados se visten como villanos clásicos de Batman.", "futuristic Gotham": "Noche Neo-Gotham: Una fiesta de estilo cyberpunk inspirada en Batman Beyond, con decoraciones de neón y gadgets futuristas." } return themes.get(category.lower(), "Idea de fiesta temática no encontrada. Prueba con 'héroes clásicos', 'mascarada de villanos' o 'Gotham futurista'.") # Instancia la herramienta party_theme_tool = SuperheroPartyThemeTool() agent = CodeAgent(tools=[party_theme_tool], model=InferenceClientModel()) # Ejecuta el agente para generar una idea de tema para la fiesta result = agent.run( "¿Cuál sería una buena idea para una fiesta de superhéroes con el tema 'mascarada de villanos'?" ) print(result) # Salida: "Baile de los Pícaros de Gotham: Una mascarada misteriosa donde los invitados se visten como villanos clásicos de Batman." ``` Con esta herramienta, ¡Alfred será el mejor anfitrión, impresionando a sus invitados con una fiesta temática de superhéroes que no olvidarán! 🦸‍♂️🦸‍♀️ ## Caja de Herramientas Predeterminada `smolagents` viene con un conjunto de herramientas preintegradas que pueden inyectarse directamente en tu agente. La [caja de herramientas predeterminada](https://huggingface.co/docs/smolagents/guided_tour?build-a-tool=Decorate+a+function+with+%40tool#default-toolbox) incluye: - **PythonInterpreterTool** - **FinalAnswerTool** - **UserInputTool** - **DuckDuckGoSearchTool** - **GoogleSearchTool** - **VisitWebpageTool** Alfred podría usar varias herramientas para asegurar una fiesta impecable en la Mansión Wayne: - Primero, podría usar la `DuckDuckGoSearchTool` para encontrar ideas creativas para fiestas temáticas de superhéroes. - Para el catering, confiaría en la `GoogleSearchTool` para encontrar los servicios mejor valorados en Gotham. - Para gestionar la distribución de asientos, Alfred podría realizar cálculos con la `PythonInterpreterTool`. - Una vez recopilado todo, compilaría el plan usando la `FinalAnswerTool`. Con estas herramientas, Alfred garantiza que la fiesta sea excepcional e impecable. 🦇💡 ## Compartir e Importar Herramientas Una de las características más poderosas de **smolagents** es su capacidad para compartir herramientas personalizadas en el Hub e integrar perfectamente herramientas creadas por la comunidad. Esto incluye la conexión con **HF Spaces** y **herramientas de LangChain**, mejorando significativamente la capacidad de Alfred para organizar una fiesta inolvidable en la Mansión Wayne. 🎭 Con estas integraciones, Alfred puede aprovechar herramientas avanzadas de planificación de eventos, ya sea ajustar la iluminación para el ambiente perfecto, seleccionar la lista de reproducción ideal para la fiesta, o coordinar con los mejores servicios de catering de Gotham. Aquí hay ejemplos que muestran cómo estas funcionalidades pueden elevar la experiencia de la fiesta: ### Compartir una Herramienta en el Hub ¡Compartir tu herramienta personalizada con la comunidad es fácil! Simplemente súbela a tu cuenta de Hugging Face usando el método `push_to_hub()`. Por ejemplo, Alfred puede compartir su `party_theme_tool` para ayudar a otros a encontrar los mejores servicios de catering en Gotham. Así es cómo hacerlo: ```python party_theme_tool.push_to_hub("{tu_nombre_de_usuario}/party_theme_tool", token="") ``` ### Importar una Herramienta desde el Hub Puedes importar fácilmente herramientas creadas por otros usuarios usando la función `load_tool()`. Por ejemplo, Alfred podría querer generar una imagen promocional para la fiesta usando IA. En lugar de construir una herramienta desde cero, puede aprovechar una predefinida de la comunidad: ```python from smolagents import load_tool, CodeAgent, InferenceClientModel image_generation_tool = load_tool( "m-ric/text-to-image", trust_remote_code=True ) agent = CodeAgent( tools=[image_generation_tool], model=InferenceClientModel() ) agent.run("Genera una imagen de una lujosa fiesta temática de superhéroes en la Mansión Wayne con superhéroes inventados.") ``` ### Importar un Hugging Face Space como Herramienta También puedes importar un HF Space como herramienta usando `Tool.from_space()`. Esto abre posibilidades para integrar miles de spaces de la comunidad para tareas desde generación de imágenes hasta análisis de datos. La herramienta se conectará con el backend Gradio del space usando `gradio_client`, así que asegúrate de instalarlo via `pip` si aún no lo tienes. Para la fiesta, Alfred puede usar un HF Space existente para la generación de la imagen generada por IA que se usará en el anuncio (en lugar de la herramienta preintegrada que mencionamos antes). ¡Vamos a construirla! ```python from smolagents import CodeAgent, InferenceClientModel, Tool image_generation_tool = Tool.from_space( "black-forest-labs/FLUX.1-schnell", name="image_generator", description="Generar una imagen a partir de un prompt" ) model = InferenceClientModel("Qwen/Qwen2.5-Coder-32B-Instruct") agent = CodeAgent(tools=[image_generation_tool], model=model) agent.run( "Mejora este prompt, luego genera una imagen del mismo.", additional_args={'user_prompt': 'Una gran fiesta temática de superhéroes en la Mansión Wayne, con Alfred supervisando una lujosa gala'} ) ``` ### Importar una Herramienta de LangChain Discutiremos el framework `LangChain` en las próximas secciones. Por ahora, solo notamos que ¡podemos reutilizar herramientas de LangChain en tu flujo de trabajo de smolagents! Puedes cargar fácilmente herramientas de LangChain usando el método `Tool.from_langchain()`. Alfred, siempre perfeccionista, está preparando una espectacular noche de superhéroes en la Mansión Wayne mientras los Wayne están fuera. Para asegurarse de que cada detalle supere las expectativas, aprovecha las herramientas de LangChain para encontrar ideas de entretenimiento de primera categoría. Al usar `Tool.from_langchain()`, Alfred añade sin esfuerzo funcionalidades de búsqueda avanzadas a su smolagent, permitiéndole descubrir ideas y servicios exclusivos para fiestas con solo unos pocos comandos. Así es como lo hace: ```python from langchain.agents import load_tools from smolagents import CodeAgent, InferenceClientModel, Tool search_tool = Tool.from_langchain(load_tools(["serpapi"])[0]) agent = CodeAgent(tools=[search_tool], model=model) agent.run("Busca ideas de entretenimiento de lujo para un evento temático de superhéroes, como actuaciones en vivo y experiencias interactivas.") ``` Con esta configuración, Alfred puede descubrir rápidamente opciones de entretenimiento lujosas, asegurando que los invitados de élite de Gotham tengan una experiencia inolvidable. ¡Esta herramienta le ayuda a organizar el evento temático de superhéroes perfecto para la Mansión Wayne! 🎉 ## Recursos - [Tutorial de Herramientas](https://huggingface.co/docs/smolagents/tutorials/tools) - Explora este tutorial para aprender a trabajar efectivamente con herramientas. - [Documentación de Herramientas](https://huggingface.co/docs/smolagents/v1.8.1/en/reference/tools) - Documentación de referencia completa sobre herramientas. - [Tour Guiado de Herramientas](https://huggingface.co/docs/smolagents/v1.8.1/en/guided_tour#tools) - Un tour guiado paso a paso para ayudarte a construir y utilizar herramientas eficientemente. - [Construyendo Agentes Efectivos](https://huggingface.co/docs/smolagents/tutorials/building_good_agents) - Una guía detallada sobre mejores prácticas para desarrollar agentes de función personalizados fiables y de alto rendimiento. ================================================ FILE: units/es/unit2/smolagents/vision_agents.mdx ================================================ # Agentes de Visión con smolagents > [!WARNING] > Los ejemplos en esta sección requieren acceso a un modelo VLM potente. Los probamos usando la API de GPT-4o. > Sin embargo, Por qué usar smolagents discute soluciones alternativas soportadas por smolagents y Hugging Face. Si deseas explorar otras opciones, asegúrate de revisar esa sección. Dotar a los agentes con capacidades visuales es crucial para resolver tareas que van más allá del procesamiento de texto. Muchos desafíos del mundo real, como la navegación web o la comprensión de documentos, requieren analizar contenido visual complejo. Afortunadamente, `smolagents` proporciona soporte integrado para modelos de visión-lenguaje (VLMs), permitiendo a los agentes procesar e interpretar imágenes de manera efectiva. En este ejemplo, imagina que Alfred, el mayordomo de la Mansión Wayne, tiene la tarea de verificar las identidades de los invitados que asisten a la fiesta. Como puedes imaginar, Alfred puede no estar familiarizado con todos los que llegan. Para ayudarlo, podemos usar un agente que verifique su identidad buscando información visual sobre su apariencia usando un VLM. Esto permitirá a Alfred tomar decisiones informadas sobre quién puede entrar. ¡Vamos a construir este ejemplo! ## Proporcionando Imágenes al Inicio de la Ejecución del Agente > [!TIP] > Puedes seguir el código en este notebook que puedes ejecutar usando Google Colab. En este enfoque, las imágenes se pasan al agente al inicio y se almacenan como `task_images` junto con el prompt de la tarea. El agente luego procesa estas imágenes durante su ejecución. Considera el caso donde Alfred quiere verificar las identidades de los superhéroes que asisten a la fiesta. Ya tiene un conjunto de datos de imágenes de fiestas anteriores con los nombres de los invitados. Dada la imagen de un nuevo visitante, el agente puede compararla con el conjunto de datos existente y tomar una decisión sobre dejarlos entrar. En este caso, un invitado está tratando de entrar, y Alfred sospecha que este visitante podría ser El Joker haciéndose pasar por Wonder Woman. Alfred necesita verificar su identidad para evitar que entren personas no deseadas. Vamos a construir el ejemplo. Primero, se cargan las imágenes. En este caso, usamos imágenes de Wikipedia para mantener el ejemplo mínimo, ¡pero imagina el posible caso de uso! ```python from PIL import Image import requests from io import BytesIO image_urls = [ "https://upload.wikimedia.org/wikipedia/commons/e/e8/The_Joker_at_Wax_Museum_Plus.jpg", # Imagen del Joker "https://upload.wikimedia.org/wikipedia/en/9/98/Joker_%28DC_Comics_character%29.jpg" # Imagen del Joker ] images = [] for url in image_urls: response = requests.get(url) image = Image.open(BytesIO(response.content)).convert("RGB") images.append(image) ``` Ahora que tenemos las imágenes, el agente nos dirá si un invitado es realmente un superhéroe (Wonder Woman) o un villano (El Joker). ```python from smolagents import CodeAgent, OpenAIServerModel model = OpenAIServerModel(model_id="gpt-4o") # Instanciar el agente agent = CodeAgent( tools=[], model=model, max_steps=20, verbosity_level=2 ) response = agent.run( """ Describe el disfraz y maquillaje que está usando el personaje de cómic en estas fotos y devuelve la descripción. Dime si el invitado es El Joker o Wonder Woman. """, images=images ) ``` En el caso de mi ejecución, la salida es la siguiente, aunque podría variar en tu caso, como ya hemos discutido: ```python { 'Disfraz y Maquillaje - Primera Imagen': ( 'Abrigo púrpura y una corbata o pañuelo de seda púrpura sobre una camisa amarillo mostaza.', 'Pintura facial blanca con rasgos exagerados, cejas oscuras, maquillaje azul en los ojos, labios rojos formando una amplia sonrisa.' ), 'Disfraz y Maquillaje - Segunda Imagen': ( 'Traje oscuro con una flor en la solapa, sosteniendo una carta de juego.', 'Piel pálida, cabello verde, labios muy rojos con una sonrisa exagerada.' ), 'Identidad del Personaje': 'Este personaje se asemeja a representaciones conocidas de El Joker de los medios de cómics.' } ``` En este caso, la salida revela que la persona se está haciendo pasar por alguien más, ¡así que podemos evitar que El Joker entre a la fiesta! ## Proporcionando Imágenes con Recuperación Dinámica > [!TIP] > Puedes seguir el código en este archivo Python El enfoque anterior es valioso y tiene muchos casos de uso potenciales. Sin embargo, en situaciones donde el invitado no está en la base de datos, necesitamos explorar otras formas de identificarlos. Una posible solución es recuperar dinámicamente imágenes e información de fuentes externas, como navegar por la web para obtener detalles. En este enfoque, las imágenes se agregan dinámicamente a la memoria del agente durante la ejecución. Como sabemos, los agentes en `smolagents` están basados en la clase `MultiStepAgent`, que es una abstracción del framework ReAct. Esta clase opera en un ciclo estructurado donde varias variables y conocimientos se registran en diferentes etapas: 1. **SystemPromptStep:** Almacena el prompt del sistema. 2. **TaskStep:** Registra la consulta del usuario y cualquier entrada proporcionada. 3. **ActionStep:** Captura registros de las acciones del agente y los resultados. Este enfoque estructurado permite a los agentes incorporar información visual de manera dinámica y responder de forma adaptativa a tareas en evolución. A continuación se muestra el diagrama que ya hemos visto, ilustrando el proceso de flujo de trabajo dinámico y cómo diferentes pasos se integran dentro del ciclo de vida del agente. Al navegar, el agente puede tomar capturas de pantalla y guardarlas como `observation_images` en el `ActionStep`. ![Recuperación dinámica de imágenes](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/smolagents-can-see/diagram_adding_vlms_smolagents.png) Ahora que entendemos la necesidad, vamos a construir nuestro ejemplo completo. En este caso, Alfred quiere control total sobre el proceso de verificación de invitados, por lo que buscar detalles se convierte en una solución viable. Para completar este ejemplo, necesitamos un nuevo conjunto de herramientas para el agente. Además, usaremos Selenium y Helium, que son herramientas de automatización de navegador. Esto nos permitirá construir un agente que explore la web, buscando detalles sobre un posible invitado y recuperando información de verificación. Vamos a instalar las herramientas necesarias: ```bash pip install "smolagents[all]" helium selenium python-dotenv ``` Necesitaremos un conjunto de herramientas de agente específicamente diseñadas para navegar, como `search_item_ctrl_f`, `go_back`, y `close_popups`. Estas herramientas permiten al agente actuar como una persona navegando por la web. ```python @tool def search_item_ctrl_f(text: str, nth_result: int = 1) -> str: """ Busca texto en la página actual a través de Ctrl + F y salta a la n-ésima ocurrencia. Args: text: El texto a buscar nth_result: A qué ocurrencia saltar (por defecto: 1) """ elements = driver.find_elements(By.XPATH, f"//*[contains(text(), '{text}')]") if nth_result > len(elements): raise Exception(f"Coincidencia n°{nth_result} no encontrada (solo se encontraron {len(elements)} coincidencias)") result = f"Se encontraron {len(elements)} coincidencias para '{text}'." elem = elements[nth_result - 1] driver.execute_script("arguments[0].scrollIntoView(true);", elem) result += f"Enfocado en el elemento {nth_result} de {len(elements)}" return result @tool def go_back() -> None: """Regresa a la página anterior.""" driver.back() @tool def close_popups() -> str: """ Cierra cualquier modal o pop-up visible en la página. ¡Usa esto para descartar ventanas emergentes! Esto no funciona en banners de consentimiento de cookies. """ webdriver.ActionChains(driver).send_keys(Keys.ESCAPE).perform() ``` También necesitamos funcionalidad para guardar capturas de pantalla, ya que esta será una parte esencial de lo que nuestro agente VLM usa para completar la tarea. Esta funcionalidad captura la pantalla y la guarda en `step_log.observations_images = [image.copy()]`, permitiendo al agente almacenar y procesar las imágenes dinámicamente mientras navega. ```python def save_screenshot(step_log: ActionStep, agent: CodeAgent) -> None: sleep(1.0) # Permitir que ocurran animaciones JavaScript antes de tomar la captura de pantalla driver = helium.get_driver() current_step = step_log.step_number if driver is not None: for step_logs in agent.logs: # Eliminar capturas de pantalla anteriores de los registros para un procesamiento eficiente if isinstance(step_log, ActionStep) and step_log.step_number <= current_step - 2: step_logs.observations_images = None png_bytes = driver.get_screenshot_as_png() image = Image.open(BytesIO(png_bytes)) print(f"Se capturó una captura de pantalla del navegador: {image.size} píxeles") step_log.observations_images = [image.copy()] # Crear una copia para asegurar que persista, ¡importante! # Actualizar observaciones con la URL actual url_info = f"URL actual: {driver.current_url}" step_log.observations = url_info if step_logs.observations is None else step_log.observations + "\n" + url_info return ``` Esta función se pasa al agente como `step_callback`, ya que se activa al final de cada paso durante la ejecución del agente. Esto permite al agente capturar y almacenar dinámicamente capturas de pantalla a lo largo de su proceso. Ahora, podemos generar nuestro agente de visión para navegar por la web, proporcionándole las herramientas que creamos, junto con el `DuckDuckGoSearchTool` para explorar la web. Esta herramienta ayudará al agente a recuperar la información necesaria para verificar las identidades de los invitados basándose en señales visuales. ```python from smolagents import CodeAgent, OpenAIServerModel, DuckDuckGoSearchTool model = OpenAIServerModel(model_id="gpt-4o") agent = CodeAgent( tools=[DuckDuckGoSearchTool(), go_back, close_popups, search_item_ctrl_f], model=model, additional_authorized_imports=["helium"], step_callbacks=[save_screenshot], max_steps=20, verbosity_level=2, ) ``` Con eso, Alfred está listo para verificar las identidades de los invitados y tomar decisiones informadas sobre si dejarlos entrar a la fiesta: ```python agent.run(""" Soy Alfred, el mayordomo de la Mansión Wayne, responsable de verificar la identidad de los invitados en la fiesta. Una superheroína ha llegado a la entrada afirmando ser Wonder Woman, pero necesito confirmar si ella es quien dice ser. Por favor, busca imágenes de Wonder Woman y genera una descripción visual detallada basada en esas imágenes. Además, navega a Wikipedia para recopilar detalles clave sobre su apariencia. Con esta información, puedo determinar si concederle acceso al evento. """ + helium_instructions) ``` Puedes ver que incluimos `helium_instructions` como parte de la tarea. Este prompt especial está destinado a controlar la navegación del agente, asegurando que siga los pasos correctos mientras navega por la web. Veamos cómo funciona esto en el video a continuación: Esta es la salida final: ```python Respuesta final: Wonder Woman normalmente se representa vistiendo un corsé rojo y dorado, shorts o falda azul con estrellas blancas, una tiara dorada, brazaletes plateados y un Lazo de la Verdad dorado. Es la Princesa Diana de Themyscira, conocida como Diana Prince en el mundo de los hombres. ``` ¡Con todo eso, hemos creado exitosamente nuestro verificador de identidad para la fiesta! Alfred ahora tiene las herramientas necesarias para asegurar que solo los invitados correctos pasen por la puerta. ¡Todo está listo para pasarlo bien en la Mansión Wayne! ## Lecturas Adicionales - [Acabamos de dar vista a smolagents](https://huggingface.co/blog/smolagents-can-see) - Blog que describe la funcionalidad del agente de visión. - [Automatización de Navegador Web con Agentes 🤖🌐](https://huggingface.co/docs/smolagents/examples/web_browser) - Ejemplo de navegación web usando un agente de visión. - [Ejemplo de Agente de Visión para Navegador Web](https://github.com/huggingface/smolagents/blob/main/src/smolagents/vision_web_browser.py) - Ejemplo de navegación web usando un agente de visión. ================================================ FILE: units/es/unit2/smolagents/why_use_smolagents.mdx ================================================ ![smolagents banner](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/smolagents/license_to_call.png) # ¿Por qué usar smolagents? En este módulo, exploraremos los pros y contras de usar [smolagents](https://huggingface.co/docs/smolagents/en/index), ayudándote a tomar una decisión informada sobre si es el framework adecuado para tus necesidades. ## ¿Qué es `smolagents`? `smolagents` es un framework simple pero potente para construir agentes de IA. Proporciona a los LLMs la _capacidad de acción_ para interactuar con el mundo real, como buscar o generar imágenes. Como aprendimos en la unidad 1, los agentes de IA son programas que utilizan LLMs para generar **'pensamientos'** basados en **'observaciones'** para realizar **'acciones'**. Exploremos cómo se implementa esto en smolagents. ### Ventajas clave de `smolagents` - **Simplicidad:** Mínima complejidad de código y abstracciones, para hacer que el framework sea fácil de entender, adoptar y extender - **Soporte flexible para LLM:** Funciona con cualquier LLM a través de la integración con herramientas de Hugging Face y APIs externas - **Enfoque centrado en el código:** Soporte de primera clase para Agentes de Código que escriben sus acciones directamente en código, eliminando la necesidad de análisis y simplificando la llamada a herramientas - **Integración con HF Hub:** Integración perfecta con Hugging Face Hub, permitiendo el uso de Espacios Gradio como herramientas ### ¿Cuándo usar smolagents? Con estas ventajas en mente, ¿cuándo deberíamos usar smolagents en lugar de otros frameworks? smolagents es ideal cuando: - Necesitas una **solución ligera y mínima.** - Quieres **experimentar rápidamente** sin configuraciones complejas. - La **lógica de tu aplicación es sencilla.** ### Acciones de Código vs. JSON A diferencia de otros frameworks donde los agentes escriben acciones en JSON, `smolagents` **se centra en llamadas a herramientas en código**, simplificando el proceso de ejecución. Esto se debe a que no hay necesidad de analizar el JSON para construir código que llame a las herramientas: la salida puede ejecutarse directamente. El siguiente diagrama ilustra esta diferencia: ![Acciones de Código vs. JSON](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/code_vs_json_actions.png) Para revisar la diferencia entre Acciones de Código vs Acciones JSON, puedes volver a visitar [la Sección de Acciones en la Unidad 1](https://huggingface.co/learn/agents-course/unit1/actions#actions-enabling-the-agent-to-engage-with-its-environment). ### Tipos de Agentes en `smolagents` Los agentes en `smolagents` operan como **agentes de múltiples pasos**. Cada [`MultiStepAgent`](https://huggingface.co/docs/smolagents/main/en/reference/agents#smolagents.MultiStepAgent) realiza: - Un pensamiento - Una llamada a herramienta y ejecución Además de usar **[CodeAgent](https://huggingface.co/docs/smolagents/main/en/reference/agents#smolagents.CodeAgent)** como el tipo principal de agente, smolagents también soporta **[ToolCallingAgent](https://huggingface.co/docs/smolagents/main/en/reference/agents#smolagents.ToolCallingAgent)**, que escribe llamadas a herramientas en JSON. Exploraremos cada tipo de agente con más detalle en las siguientes secciones. > [!TIP] > En smolagents, las herramientas se definen usando el decorador @tool que envuelve una función de Python o la clase Tool. ### Integración de Modelos en `smolagents` `smolagents` soporta una integración flexible de LLM, permitiéndote usar cualquier modelo invocable que cumpla con [ciertos criterios](https://huggingface.co/docs/smolagents/main/en/reference/models). El framework proporciona varias clases predefinidas para simplificar las conexiones de modelos: - **[TransformersModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.TransformersModel):** Implementa un pipeline local de `transformers` para una integración perfecta. - **[InferenceClientModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.InferenceClientModel):** Soporta llamadas de [inferencia sin servidor](https://huggingface.co/docs/huggingface_hub/main/en/guides/inference) a través de la [infraestructura de Hugging Face](https://huggingface.co/docs/api-inference/index), o a través de un número creciente de [proveedores de inferencia de terceros](https://huggingface.co/docs/huggingface_hub/main/en/guides/inference#supported-providers-and-tasks). - **[LiteLLMModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.LiteLLMModel):** Aprovecha [LiteLLM](https://www.litellm.ai/) para interacciones ligeras con modelos. - **[OpenAIServerModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.OpenAIServerModel):** Se conecta a cualquier servicio que ofrezca una interfaz de API de OpenAI. - **[AzureOpenAIServerModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.AzureOpenAIServerModel):** Soporta la integración con cualquier despliegue de Azure OpenAI. Esta flexibilidad asegura que los desarrolladores puedan elegir el modelo y servicio más adecuados para sus casos de uso específicos, y permite una fácil experimentación. Ahora que hemos entendido por qué y cuándo usar smolagents, ¡profundicemos en esta poderosa biblioteca! ## Recursos - [Blog de smolagents](https://huggingface.co/blog/smolagents) - Introducción a smolagents e interacciones de código ================================================ FILE: units/es/unit3/README.md ================================================ ================================================ FILE: units/es/unit3/agentic-rag/agent.mdx ================================================ # Creando tu Agente para la Gala Ahora que hemos construido todos los componentes necesarios para Alfred, es momento de unirlos en un agente completo que pueda ayudar a organizar nuestra extravagante gala. En esta sección, combinaremos la recuperación de información de invitados, búsqueda web, información meteorológica y herramientas de estadísticas de Hub en un solo agente poderoso. ## Ensamblando a Alfred: El Agente Completo En lugar de reimplementar todas las herramientas que creamos en secciones anteriores, las importaremos desde sus respectivos módulos que guardamos en los archivos `tools.py` y `retriever.py`. > [!TIP] > Si aún no has implementado las herramientas, regresa a las secciones de herramientas y recuperador para implementarlas, y agrégalas a los archivos tools.py y retriever.py. Importemos las bibliotecas y herramientas necesarias de las secciones anteriores: ```python # Importar librerías necesarias import random from smolagents import CodeAgent, InferenceClientModel # Importar nuestras herramientas personalizadas desde sus módulos from tools import DuckDuckGoSearchTool, WeatherInfoTool, HubStatsTool from retriever import load_guest_dataset ``` Ahora, combinemos todas estas herramientas en un solo agente: ```python # Inicializar el modelo de Hugging Face model = InferenceClientModel() # Inicializar la herramienta de búsqueda web search_tool = DuckDuckGoSearchTool() # Inicializar la herramienta del clima weather_info_tool = WeatherInfoTool() # Inicializar la herramienta de estadísticas de Hub hub_stats_tool = HubStatsTool() # Cargar el conjunto de datos de invitados e inicializar la herramienta de información de invitados guest_info_tool = load_guest_dataset() # Crear a Alfred con todas las herramientas alfred = CodeAgent( tools=[guest_info_tool, weather_info_tool, hub_stats_tool, search_tool], model=model, add_base_tools=True, # Agregar cualquier herramienta base adicional planning_interval=3 # Habilitar planificación cada 3 pasos ) ``` ```python # Importar librerías necesarias from llama_index.core.agent.workflow import AgentWorkflow from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI from tools import search_tool, weather_info_tool, hub_stats_tool from retriever import guest_info_tool ``` Ahora, combinemos todas estas herramientas en un solo agente: ```python # Inicializar el modelo de Hugging Face llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") # Crear Alfred con todas las herramientas alfred = AgentWorkflow.from_tools_or_functions( [guest_info_tool, search_tool, weather_info_tool, hub_stats_tool], llm=llm, ) ``` ```python from typing import TypedDict, Annotated from langgraph.graph.message import add_messages from langchain_core.messages import AnyMessage, HumanMessage, AIMessage from langgraph.prebuilt import ToolNode from langgraph.graph import START, StateGraph from langgraph.prebuilt import tools_condition from langchain_huggingface import HuggingFaceEndpoint, ChatHuggingFace from tools import DuckDuckGoSearchTool, weather_info_tool, hub_stats_tool from retriever import load_guest_dataset ``` Ahora, combina todas estas herramientas en un solo agente: ```python # Inicializar la herramienta de búsqueda web search_tool = DuckDuckGoSearchTool() # Cargar el conjunto de datos de invitados e inicializar la herramienta de información de invitados guest_info_tool = load_guest_dataset() # Generar la interfaz de chat, incluyendo las herramientas llm = HuggingFaceEndpoint( repo_id="Qwen/Qwen2.5-Coder-32B-Instruct", huggingfacehub_api_token=HUGGINGFACEHUB_API_TOKEN, ) chat = ChatHuggingFace(llm=llm, verbose=True) tools = [guest_info_tool, search_tool, weather_info_tool, hub_stats_tool] chat_with_tools = chat.bind_tools(tools) # Generar el AgentState y el grafo del Agente class AgentState(TypedDict): messages: Annotated[list[AnyMessage], add_messages] def assistant(state: AgentState): return { "messages": [chat_with_tools.invoke(state["messages"])], } ## El grafo builder = StateGraph(AgentState) # Definir nodos: estos hacen el trabajo builder.add_node("assistant", assistant) builder.add_node("tools", ToolNode(tools)) # Definir bordes: estos determinan cómo se mueve el flujo de control builder.add_edge(START, "assistant") builder.add_conditional_edges( "assistant", # Si el último mensaje requiere una herramienta, enrutar a herramientas # De lo contrario, proporcionar una respuesta directa tools_condition, ) builder.add_edge("tools", "assistant") alfred = builder.compile() ``` ¡Tu agente ahora está listo para usarse! ## Usando a Alfred: Ejemplos de Principio a Fin Ahora que Alfred está completamente equipado con todas las herramientas necesarias, veamos cómo puede ayudar con varias tareas durante la gala. ### Ejemplo 1: Encontrando Información de Invitados Veamos cómo Alfred puede ayudarnos con nuestra información de invitados. ```python query = "Cuéntame sobre 'Lady Ada Lovelace'" response = alfred.run(query) print("🎩 Respuesta de Alfred:") print(response) ``` Salida esperada: ``` 🎩 Respuesta de Alfred: Según la información que recuperé, Lady Ada Lovelace es una estimada matemática y amiga. Es reconocida por su trabajo pionero en matemáticas y computación, frecuentemente celebrada como la primera programadora de computadoras debido a su trabajo en el Motor Analítico de Charles Babbage. Su dirección de correo electrónico es ada.lovelace@example.com. ``` ```python query = "Cuéntame sobre Lady Ada Lovelace. ¿Cuál es su historia?" response = await alfred.run(query) print("🎩 Respuesta de Alfred:") print(response.response.blocks[0].text) ``` Salida esperada: ``` 🎩 Respuesta de Alfred: Lady Ada Lovelace fue una matemática y escritora inglesa, mejor conocida por su trabajo en el Motor Analítico de Charles Babbage. Fue la primera en reconocer que la máquina tenía aplicaciones más allá del cálculo puro. ``` ```python response = alfred.invoke({"messages": "Cuéntame sobre 'Lady Ada Lovelace'"}) print("🎩 Respuesta de Alfred:") print(response['messages'][-1].content) ``` Salida esperada: ``` 🎩 Respuesta de Alfred: Ada Lovelace, también conocida como Augusta Ada King, Condesa de Lovelace, fue una matemática y escritora inglesa. Nacida el 10 de diciembre de 1815 y fallecida el 27 de noviembre de 1852, es reconocida por su trabajo en el Motor Analítico de Charles Babbage, una computadora mecánica de propósito general. Ada Lovelace es celebrada como una de las primeras programadoras de computadoras porque creó un programa para el Motor Analítico en 1843. Reconoció que la máquina podía usarse para más que simples cálculos, visualizando su potencial de una manera que pocos hicieron en ese momento. Sus contribuciones al campo de la ciencia de la computación sentaron las bases para desarrollos futuros. Un día en octubre, designado como el Día de Ada Lovelace, honra las contribuciones de las mujeres a la ciencia y la tecnología, inspirado en el trabajo pionero de Lovelace. ``` ### Ejemplo 2: Verificando el Clima para los Fuegos Artificiales Veamos cómo Alfred puede ayudarnos con el clima. ```python query = "¿Cómo está el clima en París esta noche? ¿Será adecuado para nuestro espectáculo de fuegos artificiales?" response = alfred.run(query) print("🎩 Respuesta de Alfred:") print(response) ``` Salida esperada (variará debido a la aleatoriedad): ``` 🎩 Respuesta de Alfred: He revisado el clima en París para ti. Actualmente, está despejado con una temperatura de 25°C. Estas condiciones son perfectas para el espectáculo de fuegos artificiales de esta noche. Los cielos despejados proporcionarán una excelente visibilidad para el espectáculo espectacular, y la temperatura agradable asegurará que los invitados puedan disfrutar del evento al aire libre sin incomodidad. ``` ```python query = "¿Cómo está el clima en París esta noche? ¿Será adecuado para nuestro espectáculo de fuegos artificiales?" response = await alfred.run(query) print("🎩 Respuesta de Alfred:") print(response) ``` Salida esperada: ``` 🎩 Respuesta de Alfred: El clima en París esta noche es lluvioso con una temperatura de 15°C. Debido a la lluvia, puede que no sea adecuado para un espectáculo de fuegos artificiales. ``` ```python response = alfred.invoke({"messages": "¿Cómo está el clima en París esta noche? ¿Será adecuado para nuestro espectáculo de fuegos artificiales?"}) print("🎩 Respuesta de Alfred:") print(response['messages'][-1].content) ``` Salida esperada: ``` 🎩 Respuesta de Alfred: El clima en París esta noche es lluvioso con una temperatura de 15°C, lo que puede no ser adecuado para tu espectáculo de fuegos artificiales. ``` ### Ejemplo 3: Impresionando a Investigadores de IA Veamos cómo Alfred puede ayudarnos a impresionar a los investigadores de IA. ```python query = "Uno de nuestros invitados es de Qwen. ¿Qué puedes decirme sobre su modelo más popular?" response = alfred.run(query) print("🎩 Respuesta de Alfred:") print(response) ``` Salida esperada: ``` 🎩 Respuesta de Alfred: El modelo más popular de Qwen es Qwen/Qwen2.5-VL-7B-Instruct con 3,313,345 descargas. ``` ```python query = "Uno de nuestros invitados es de Google. ¿Qué puedes decirme sobre su modelo más popular?" response = await alfred.run(query) print("🎩 Respuesta de Alfred:") print(response) ``` Salida esperada: ``` 🎩 Respuesta de Alfred: El modelo más popular de Google en Hugging Face Hub es google/electra-base-discriminator, con 28,546,752 descargas. ``` ```python response = alfred.invoke({"messages": "Uno de nuestros invitados es de Qwen. ¿Qué puedes decirme sobre su modelo más popular?"}) print("🎩 Respuesta de Alfred:") print(response['messages'][-1].content) ``` Salida esperada: ``` 🎩 Respuesta de Alfred: El modelo más descargado de Qwen es Qwen/Qwen2.5-VL-7B-Instruct con 3,313,345 descargas. ``` ### Ejemplo 4: Combinando Múltiples Herramientas Veamos cómo Alfred puede ayudarnos a prepararnos para una conversación con el Dr. Nikola Tesla. ```python query = "Necesito hablar con el Dr. Nikola Tesla sobre avances recientes en energía inalámbrica. ¿Puedes ayudarme a prepararme para esta conversación?" response = alfred.run(query) print("🎩 Respuesta de Alfred:") print(response) ``` Salida esperada: ``` 🎩 Respuesta de Alfred: He reunido información para ayudarte a prepararte para tu conversación con el Dr. Nikola Tesla. Información del Invitado: Nombre: Dr. Nikola Tesla Relación: viejo amigo de los días universitarios Descripción: El Dr. Nikola Tesla es un viejo amigo de tus días universitarios. Recientemente ha patentado un nuevo sistema de transmisión de energía inalámbrica y estaría encantado de discutirlo contigo. Solo recuerda que le apasionan las palomas, así que eso podría ser un buen tema para iniciar la conversación. Email: nikola.tesla@gmail.com Avances Recientes en Energía Inalámbrica: Basándome en mi búsqueda web, aquí hay algunos desarrollos recientes en transmisión de energía inalámbrica: 1. Los investigadores han avanzado en la transmisión de energía inalámbrica de largo alcance utilizando ondas electromagnéticas enfocadas 2. Varias empresas están desarrollando tecnologías de acoplamiento inductivo resonante para electrónica de consumo 3. Hay nuevas aplicaciones en la carga de vehículos eléctricos sin conexiones físicas Iniciadores de Conversación: 1. "Me encantaría conocer tu nueva patente sobre transmisión de energía inalámbrica. ¿Cómo se compara con tus conceptos originales de nuestros días universitarios?" 2. "¿Has visto los desarrollos recientes en acoplamiento inductivo resonante para electrónica de consumo? ¿Qué opinas de su enfoque?" 3. "¿Cómo están tus palomas? Recuerdo tu fascinación por ellas." Esto debería darte mucho para discutir con el Dr. Tesla mientras demuestras tu conocimiento de sus intereses y desarrollos recientes en su campo. ``` ```python query = "Necesito hablar con el Dr. Nikola Tesla sobre avances recientes en energía inalámbrica. ¿Puedes ayudarme a prepararme para esta conversación?" response = await alfred.run(query) print("🎩 Respuesta de Alfred:") print(response) ``` Salida esperada: ``` 🎩 Respuesta de Alfred: Aquí hay algunos avances recientes en energía inalámbrica que podrían serte útiles para tu conversación con el Dr. Nikola Tesla: 1. **Avances y Desafíos en la Transferencia de Energía Inalámbrica**: Este artículo analiza la evolución de la transferencia de energía inalámbrica (WPT) desde los métodos convencionales con cables hasta las aplicaciones modernas, incluidas las estaciones de energía espacial solar. Destaca el enfoque inicial en la tecnología de microondas y la demanda actual de WPT debido al aumento de dispositivos eléctricos. 2. **Avances Recientes en Tecnologías de Transferencia de Energía Inalámbrica para Electrónica Corporal**: Este artículo explora la transferencia de energía inalámbrica (WET) como solución para alimentar dispositivos electrónicos corporales sin necesidad de baterías o cables conductores. Analiza las ventajas y posibles aplicaciones de WET en este contexto. 3. **Transferencia de Energía Inalámbrica y Captación de Energía: Estado Actual y Tendencias Futuras**: Este artículo proporciona una visión general de los avances recientes en métodos de suministro de energía inalámbrica, incluida la captación de energía y la transferencia de energía inalámbrica. Presenta varias aplicaciones prometedoras y analiza las tendencias futuras en el campo. 4. **Transferencia de Energía Inalámbrica: Aplicaciones, Desafíos, Barreras y ``` ```python response = alfred.invoke({"messages":"Necesito hablar con el 'Dr. Nikola Tesla' sobre avances recientes en energía inalámbrica. ¿Puedes ayudarme a prepararme para esta conversación?"}) print("🎩 Respuesta de Alfred:") print(response['messages'][-1].content) ``` Salida esperada: ``` Basándome en la información proporcionada, aquí hay puntos clave para prepararte para la conversación con el 'Dr. Nikola Tesla' sobre avances recientes en energía inalámbrica: 1. **Transmisión de Energía Inalámbrica (WPT):** Comenta cómo WPT revoluciona la transferencia de energía al eliminar la necesidad de cables y aprovechar mecanismos como el acoplamiento inductivo y resonante. 2. **Avances en Carga Inalámbrica:** Destaca las mejoras en eficiencia, velocidades de carga más rápidas y el auge de soluciones de carga inalámbrica certificadas Qi/Qi2. 3. **Innovaciones 5G-Advanced y Protocolo Inalámbrico NearLink:** Menciona estos como desarrollos que mejoran la velocidad, seguridad y eficiencia en redes inalámbricas, que pueden soportar tecnologías avanzadas de energía inalámbrica. 4. **IA y ML en el Edge:** Habla sobre cómo la inteligencia artificial y el aprendizaje automático dependerán de redes inalámbricas para llevar inteligencia al borde, mejorando la automatización e inteligencia en hogares y edificios inteligentes. 5. **Avances en Matter, Thread y Seguridad:** Comenta estas innovaciones clave que impulsan la conectividad, eficiencia y seguridad en dispositivos y sistemas IoT. 6. **Avances en Tecnología de Carga Inalámbrica:** Incluye avances recientes o estudios, como el de la Universidad Nacional de Incheon, para respaldar los avances en carga inalámbrica. ``` ### Ejemplo 3: Impresionando a Investigadores de IA Veamos cómo Alfred puede ayudarnos a impresionar a los investigadores de IA. ```python query = "Uno de nuestros invitados es de Qwen. ¿Qué puedes decirme sobre su modelo más popular?" response = alfred.run(query) print("🎩 Respuesta de Alfred:") print(response) ``` Salida esperada: ``` 🎩 Respuesta de Alfred: El modelo más popular de Qwen es Qwen/Qwen2.5-VL-7B-Instruct con 3,313,345 descargas. ``` ```python query = "Uno de nuestros invitados es de Google. ¿Qué puedes decirme sobre su modelo más popular?" response = await alfred.run(query) print("🎩 Respuesta de Alfred:") print(response) ``` Salida esperada: ``` 🎩 Respuesta de Alfred: El modelo más popular de Google en Hugging Face Hub es google/electra-base-discriminator, con 28,546,752 descargas. ``` ```python response = alfred.invoke({"messages": "Uno de nuestros invitados es de Qwen. ¿Qué puedes decirme sobre su modelo más popular?"}) print("🎩 Respuesta de Alfred:") print(response['messages'][-1].content) ``` Salida esperada: ``` 🎩 Respuesta de Alfred: El modelo más descargado de Qwen es Qwen/Qwen2.5-VL-7B-Instruct con 3,313,345 descargas. ``` ## Características Avanzadas: Memoria de Conversación Para hacer que Alfred sea aún más útil durante la gala, podemos habilitar la memoria de conversación para que recuerde interacciones previas: ```python # Crear Alfred con memoria de conversación alfred_with_memory = CodeAgent( tools=[guest_info_tool, weather_info_tool, hub_stats_tool, search_tool], model=model, add_base_tools=True, planning_interval=3, memory=True # Habilitar memoria de conversación ) # Primera interacción response1 = alfred_with_memory.run("Cuéntame sobre Lady Ada Lovelace.") print("🎩 Primera Respuesta de Alfred:") print(response1) # Segunda interacción (haciendo referencia a la primera) response2 = alfred_with_memory.run("¿En qué proyectos está trabajando actualmente?") print("🎩 Segunda Respuesta de Alfred:") print(response2) ``` ```python from llama_index.core.workflow import Context alfred = AgentWorkflow.from_tools_or_functions( [guest_info_tool, search_tool, weather_info_tool, hub_stats_tool], llm=llm ) # Recordando el estado ctx = Context(alfred) # Primera interacción response1 = await alfred.run("Cuéntame sobre Lady Ada Lovelace.", ctx=ctx) print("🎩 Primera Respuesta de Alfred:") print(response1) # Segunda interacción (haciendo referencia a la primera) response2 = await alfred.run("¿En qué proyectos está trabajando actualmente?", ctx=ctx) print("🎩 Segunda Respuesta de Alfred:") print(response2) ``` ```python # Primera interacción response = alfred.invoke({"messages": [HumanMessage(content="Cuéntame sobre 'Lady Ada Lovelace'. ¿Cuál es su historia y cómo está relacionada conmigo?")]}) print("🎩 Respuesta de Alfred:") print(response['messages'][-1].content) print() # Segunda interacción (haciendo referencia a la primera) response = alfred.invoke({"messages": response["messages"] + [HumanMessage(content="¿En qué proyectos está trabajando actualmente?")]}) print("🎩 Respuesta de Alfred:") print(response['messages'][-1].content) ``` ## Conclusión ¡Felicitaciones! Has construido exitosamente a Alfred, un agente sofisticado equipado con múltiples herramientas para ayudar a organizar la gala más extravagante del siglo. Alfred ahora puede: 1. Recuperar información detallada sobre los invitados 2. Verificar las condiciones climáticas para planificar actividades al aire libre 3. Proporcionar información sobre influyentes creadores de IA y sus modelos 4. Buscar en la web la información más reciente 5. Mantener el contexto de la conversación con memoria Con estas capacidades, Alfred está listo para asegurar que tu gala sea un éxito rotundo, impresionando a los invitados con atención personalizada e información actualizada. ================================================ FILE: units/es/unit3/agentic-rag/agentic-rag.mdx ================================================ # Generación Aumentada por Recuperación con Agentes (RAG Agéntico) En esta unidad, veremos cómo podemos usar RAG Agéntico para ayudar a Alfred a prepararse para la increíble gala. > [!TIP] > Sabemos que ya hemos discutido la Generación Aumentada por Recuperación (RAG) y RAG agéntico en la unidad anterior, así que siéntete libre de avanzar si ya estás familiarizado con los conceptos. Los LLMs están entrenados en enormes volúmenes de datos para aprender conocimiento general. Sin embargo, el modelo de conocimiento del mundo de los LLMs no siempre puede contener información relevante y actualizada. **RAG resuelve este problema encontrando y recuperando información relevante de tus datos y enviándola al LLM.** ![RAG](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/rag.png) Ahora, piensa en cómo funciona Alfred: 1. Le hemos pedido a Alfred que ayude a planificar una gala 2. Alfred necesita encontrar las últimas noticias e información meteorológica 3. Alfred necesita estructurar y buscar la información de los invitados Así como Alfred necesita buscar en la información de tu hogar para ser útil, cualquier agente necesita una manera de encontrar y comprender datos relevantes. **RAG Agéntico es una forma poderosa de usar agentes para responder preguntas sobre tus datos.** Podemos proporcionar varias herramientas a Alfred para ayudarlo a responder preguntas. Sin embargo, en lugar de responder automáticamente a la pregunta basada en documentos, Alfred puede decidir usar cualquier otra herramienta o flujo para responder la pregunta. ![RAG Agéntico](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/agentic-rag.png) ¡Comencemos a **construir nuestro flujo de trabajo de RAG agéntico!** Primero, crearemos una herramienta RAG para recuperar detalles actualizados sobre los invitados. Luego, desarrollaremos herramientas para búsqueda web, actualizaciones meteorológicas y estadísticas de descargas de modelos de Hugging Face Hub. Finalmente, integraremos todo para dar vida a nuestro agente RAG agéntico! ================================================ FILE: units/es/unit3/agentic-rag/conclusion.mdx ================================================ # Conclusión En esta unidad, hemos aprendido a crear un sistema RAG agéntico para ayudar a Alfred, nuestro amigable agente de vecindario, a prepararse y a gestionar una gala extravagante. La combinación de RAG con las capacidades agéntico demuestra cómo los asistentes de IA pueden volverse muy poderosos cuando tienen: - Acceso a conocimientos estructurados (información de los invitados) - Capacidad de recuperar información en tiempo real (búsqueda web) - Herramientas específicas del dominio (información climática, estadísticas de Hub) - Memoria de las interacciones pasadas Con estas capacidades, Alfred está bien equipado para ser el perfecto anfitrión, capaz de responder a preguntas sobre los invitados, proporcionar información actualizada y asegurarse de que la gala se realice sin problemas -incluso gestionando el momento perfecto para el lanzamiento de los fuegos artificiales! > [!TIP] > Ahora que has construido un agente completo, podrías querer explorar: > > - Crear herramientas especializadas para tus propios casos de uso > - Implementar sistemas RAG más sofisticados con embeddings > - Crear sistemas multi-agente donde los agentes puedan colaborar > - Desplegar tu agente como un servicio con el que los demás puedan interactuar ================================================ FILE: units/es/unit3/agentic-rag/introduction.mdx ================================================ # Introducción al Caso de Uso para RAG Agéntico ![Banner de RAG Agéntico](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit3/agentic-rag/thumbnail.jpg) En esta unidad, ayudaremos a Alfred, nuestro amigable agente que está organizando la gala, utilizando RAG Agéntico para crear una herramienta que pueda usarse para responder preguntas sobre los invitados en la gala. > [!TIP] > Este es un caso de uso 'del mundo real' para RAG Agéntico, que podrías utilizar en tus propios proyectos o lugares de trabajo. Si quieres obtener más de este proyecto, ¿por qué no lo pruebas en tu propio caso de uso y lo compartes en Discord? Puedes elegir cualquiera de los frameworks discutidos en el curso para este caso de uso. Proporcionamos ejemplos de código para cada uno en pestañas separadas. ## Una Gala para Recordar Ahora, es momento de ensuciarnos las manos con un caso de uso real. ¡Preparemos el escenario! **Has decidido organizar la fiesta más extravagante y opulenta del siglo.** Esto significa banquetes lujosos, bailarines encantadores, DJs de renombre, bebidas exquisitas, un impresionante espectáculo de fuegos artificiales y mucho más. Alfred, tu amigable agente de vecindario, se está preparando para atender todas tus necesidades para esta fiesta, y **Alfred va a gestionar todo por sí mismo**. Para hacerlo, necesita tener acceso a toda la información sobre la fiesta, incluyendo el menú, los invitados, el horario, pronósticos del clima, ¡y mucho más! No solo eso, sino que también necesita asegurarse de que la fiesta sea un éxito, por lo que **necesita poder responder cualquier pregunta sobre la fiesta durante la fiesta**, mientras maneja situaciones inesperadas que puedan surgir. No puede hacer esto solo, así que debemos asegurarnos de que Alfred tenga acceso a toda la información y herramientas que necesita. Primero, vamos a darle una lista de requisitos estrictos para la gala. ## Los Requisitos de la Gala Una persona debidamente educada en la época del **Renacimiento** necesita tener tres rasgos principales. Él o ella necesitaba ser profundo en el **conocimiento de deportes, cultura y ciencia**. Por lo tanto, debemos asegurarnos de que podamos impresionar a nuestros invitados con nuestro conocimiento y proporcionarles una gala verdaderamente inolvidable. Sin embargo, para evitar conflictos, hay algunos **temas, como la política y la religión, que deben evitarse en una gala.** Debe ser una fiesta divertida sin conflictos relacionados con creencias e ideales. Según la etiqueta, **un buen anfitrión debe conocer los antecedentes de los invitados**, incluyendo sus intereses y esfuerzos. Un buen anfitrión también chismea y comparte historias sobre los invitados entre sí. Por último, debemos asegurarnos de tener **algún conocimiento general sobre el clima** para poder encontrar continuamente una actualización en tiempo real que asegure el momento perfecto para lanzar los fuegos artificiales y terminar la gala con broche de oro. 🎆 Como puedes ver, Alfred necesita mucha información para organizar la gala. Afortunadamente, podemos ayudar y preparar a Alfred dándole algo de **entrenamiento en Generación Aumentada por Recuperación (RAG)**. ¡Comencemos creando las herramientas que Alfred necesita para poder organizar la gala! ================================================ FILE: units/es/unit3/agentic-rag/invitees.mdx ================================================ # Creando una Herramienta RAG para Historias de Invitados Alfred, tu agente de confianza, está preparando la gala más extravagante del siglo. Para asegurar que el evento transcurra sin problemas, Alfred necesita acceso rápido a información actualizada sobre cada invitado. Ayudemos a Alfred creando una herramienta personalizada de Generación Aumentada por Recuperación (RAG), impulsada por nuestro conjunto de datos personalizado. ## ¿Por qué RAG para una Gala? Imagina a Alfred mezclándose entre los invitados, necesitando recordar detalles específicos sobre cada persona en un instante. Un LLM tradicional podría tener dificultades con esta tarea porque: 1. La lista de invitados es específica para tu evento y no está en los datos de entrenamiento del modelo 2. La información de los invitados puede cambiar o actualizarse frecuentemente 3. Alfred necesita recuperar detalles precisos como direcciones de correo electrónico Aquí es donde brilla la Generación Aumentada por Recuperación (RAG)! Al combinar un sistema de recuperación con un LLM, Alfred puede acceder a información precisa y actualizada sobre tus invitados bajo demanda. > [!TIP] > Puedes elegir cualquiera de los frameworks cubiertos en el curso para este caso de uso. Selecciona tu opción preferida de las pestañas de código. ## Configurando nuestra aplicación En esta unidad, desarrollaremos nuestro agente dentro de un Espacio de HF(HF Space), como un proyecto Python estructurado. Este enfoque nos ayuda a mantener un código limpio y modular, organizando diferentes funcionalidades en archivos separados. Además, esto crea un caso de uso más realista donde desplegarías la aplicación para uso público. ### Estructura del Proyecto - **`tools.py`** – Proporciona herramientas auxiliares para el agente. - **`retriever.py`** – Implementa funciones de recuperación para apoyar el acceso al conocimiento. - **`app.py`** – Integra todos los componentes en un agente completamente funcional, que finalizaremos en la última parte de esta unidad. Para una referencia práctica, consulta [este Espacio de HF](https://huggingface.co/spaces/agents-course/Unit_3_Agentic_RAG), donde el RAG Agéntico desarrollado en esta unidad está en vivo. ¡Siéntete libre de clonarlo y experimentar! Puedes probar directamente el agente a continuación: ## Descripción General del Conjunto de Datos Nuestro conjunto de datos [`agents-course/unit3-invitees`](https://huggingface.co/datasets/agents-course/unit3-invitees/) contiene los siguientes campos para cada invitado: - **Nombre**: Nombre completo del invitado - **Relación**: Cómo se relaciona el invitado con el anfitrión - **Descripción**: Una breve biografía o hechos interesantes sobre el invitado - **Dirección de Correo Electrónico**: Información de contacto para enviar invitaciones o seguimientos A continuación se muestra una vista previa del conjunto de datos: > [!TIP] > En un escenario del mundo real, este conjunto de datos podría ampliarse para incluir preferencias dietéticas, intereses de regalos, temas de conversación a evitar y otros detalles útiles para un anfitrión. ## Construyendo la Herramienta de Lista de Invitados Crearemos una herramienta personalizada que Alfred pueda usar para recuperar rápidamente información de los invitados durante la gala. Dividamos esto en tres pasos manejables: 1. Cargar y preparar el conjunto de datos 2. Crear la Herramienta de Recuperación 3. Integrar la Herramienta con Alfred ¡Comencemos con la carga y preparación del conjunto de datos! ### Paso 1: Cargar y Preparar el Conjunto de Datos Primero, necesitamos transformar nuestros datos brutos de invitados en un formato optimizado para la recuperación. Usaremos la librería `datasets` de Hugging Face para cargar el conjunto de datos y convertirlo en una lista de objetos `Document` del módulo `langchain.docstore.document`. ```python import datasets from langchain_core.documents import Document # Cargar el conjunto de datos guest_dataset = datasets.load_dataset("agents-course/unit3-invitees", split="train") # Convertir entradas del conjunto de datos en objetos Document docs = [ Document( page_content="\n".join([ f"Name: {guest['name']}", f"Relation: {guest['relation']}", f"Description: {guest['description']}", f"Email: {guest['email']}" ]), metadata={"name": guest["name"]} ) for guest in guest_dataset ] ``` Usaremos la librería `datasets` de Hugging Face para cargar el conjunto de datos y convertirlo en una lista de objetos `Document` del módulo `llama_index.core.schema`. ```python import datasets from llama_index.core.schema import Document # Cargar el conjunto de datos guest_dataset = datasets.load_dataset("agents-course/unit3-invitees", split="train") # Convertir entradas del conjunto de datos en objetos Document docs = [ Document( text="\n".join([ f"Name: {guest_dataset['name'][i]}", f"Relation: {guest_dataset['relation'][i]}", f"Description: {guest_dataset['description'][i]}", f"Email: {guest_dataset['email'][i]}" ]), metadata={"name": guest_dataset['name'][i]} ) for i in range(len(guest_dataset)) ] ``` Usaremos la librería `datasets` de Hugging Face para cargar el conjunto de datos y convertirlo en una lista de objetos `Document` del módulo `langchain.docstore.document`. ```python import datasets from langchain_core.documents import Document # Cargar el conjunto de datos guest_dataset = datasets.load_dataset("agents-course/unit3-invitees", split="train") # Convertir entradas del conjunto de datos en objetos Document docs = [ Document( page_content="\n".join([ f"Name: {guest['name']}", f"Relation: {guest['relation']}", f"Description: {guest['description']}", f"Email: {guest['email']}" ]), metadata={"name": guest["name"]} ) for guest in guest_dataset ] ``` En el código anterior: - Cargamos el conjunto de datos - Convertimos cada entrada de invitado en un objeto `Document` con contenido formateado - Almacenamos los objetos `Document` en una lista Esto significa que tenemos todos nuestros datos disponibles de manera ordenada para poder comenzar a configurar nuestra recuperación. ### Paso 2: Crear la Herramienta de Recuperación Ahora, creemos una herramienta personalizada que Alfred pueda usar para buscar en nuestra información de invitados. Usaremos el `BM25Retriever` del módulo `langchain_community.retrievers` para crear una herramienta de recuperación. > [!TIP] > El BM25Retriever es un gran punto de partida para la recuperación, pero para búsquedas semánticas más avanzadas, podrías considerar usar recuperadores basados en embeddings como los de sentence-transformers. ```python from smolagents import Tool from langchain_community.retrievers import BM25Retriever class GuestInfoRetrieverTool(Tool): name = "guest_info_retriever" description = "Recupera información detallada sobre los invitados de la gala basada en su nombre o relación." inputs = { "query": { "type": "string", "description": "El nombre o relación del invitado sobre el que deseas información." } } output_type = "string" def __init__(self, docs): self.is_initialized = False self.retriever = BM25Retriever.from_documents(docs) def forward(self, query: str): results = self.retriever.get_relevant_documents(query) if results: return "\n\n".join([doc.page_content for doc in results[:3]]) else: return "No se encontró información que coincida con la búsqueda." # Inicializar la herramienta guest_info_tool = GuestInfoRetrieverTool(docs) ``` Entendamos esta herramienta paso a paso: - El `name` y la `description` ayudan al agente a entender cuándo y cómo usar esta herramienta - Los `inputs` definen qué parámetros espera la herramienta (en este caso, una consulta de búsqueda) - Estamos usando un `BM25Retriever`, que es un algoritmo poderoso de recuperación de texto que no requiere embeddings - El método `forward` procesa la consulta y devuelve la información más relevante del invitado Usaremos el `BM25Retriever` del módulo `llama_index.retrievers.bm25` para crear una herramienta de recuperación. > [!TIP] > El BM25Retriever es un gran punto de partida para la recuperación, pero para búsquedas semánticas más avanzadas, podrías considerar usar recuperadores basados en embeddings como los de sentence-transformers. ```python from llama_index.core.tools import FunctionTool from llama_index.retrievers.bm25 import BM25Retriever bm25_retriever = BM25Retriever.from_defaults(nodes=docs) def get_guest_info_retriever(query: str) -> str: """Recupera información detallada sobre los invitados de la gala basada en su nombre o relación.""" results = bm25_retriever.retrieve(query) if results: return "\n\n".join([doc.text for doc in results[:3]]) else: return "No se encontró información que coincida con la búsqueda." # Inicializar la herramienta guest_info_tool = FunctionTool.from_defaults(get_guest_info_retriever) ``` Entendamos esta herramienta paso a paso: - El docstring ayuda al agente a entender cuándo y cómo usar esta herramienta - Los decoradores de tipo definen qué parámetros espera la herramienta (en este caso, una consulta de búsqueda) - Estamos usando un `BM25Retriever`, que es un algoritmo poderoso de recuperación de texto que no requiere embeddings - El método procesa la consulta y devuelve la información más relevante del invitado Usaremos el `BM25Retriever` del módulo `langchain_community.retrievers` para crear una herramienta de recuperación. > [!TIP] > El BM25Retriever es un gran punto de partida para la recuperación, pero para búsquedas semánticas más avanzadas, podrías considerar usar recuperadores basados en embeddings como los de sentence-transformers. ```python from langchain_community.retrievers import BM25Retriever from langchain_core.tools import Tool bm25_retriever = BM25Retriever.from_documents(docs) def extract_text(query: str) -> str: """Recupera información detallada sobre los invitados de la gala basada en su nombre o relación.""" results = bm25_retriever.invoke(query) if results: return "\n\n".join([doc.text for doc in results[:3]]) else: return "No se encontró información que coincida con la búsqueda." guest_info_tool = Tool( name="guest_info_retriever", func=extract_text, description="Recupera información detallada sobre los invitados de la gala basada en su nombre o relación." ) ``` Entendamos esta herramienta paso a paso: - El `name` y la `description` ayudan al agente a entender cuándo y cómo usar esta herramienta - Los decoradores de tipo definen qué parámetros espera la herramienta (en este caso, una consulta de búsqueda) - Estamos usando un `BM25Retriever`, que es un potente algoritmo de recuperación de texto que no requiere embeddings - El método procesa la consulta y devuelve la información más relevante del invitado ### Paso 3: Integrar la Herramienta con Alfred Finalmente, juntemos todo creando nuestro agente y equipándolo con nuestra herramienta personalizada: ```python from smolagents import CodeAgent, InferenceClientModel # Inicializar el modelo de Hugging Face model = InferenceClientModel() # Crear Alfred, nuestro agente de gala, con la herramienta de información de invitados alfred = CodeAgent(tools=[guest_info_tool], model=model) # Ejemplo de consulta que Alfred podría recibir durante la gala response = alfred.run("Cuéntame sobre nuestra invitada llamada 'Lady Ada Lovelace'.") print("🎩 Respuesta de Alfred:") print(response) ``` Salida esperada: ``` 🎩 Respuesta de Alfred: Basado en la información que recuperé, Lady Ada Lovelace es una estimada matemática y amiga. Es reconocida por su trabajo pionero en matemáticas e informática, a menudo celebrada como la primera programadora de computadoras debido a su trabajo en la Máquina Analítica de Charles Babbage. Su dirección de correo electrónico es ada.lovelace@example.com. ``` Lo que está sucediendo en este paso final: - Inicializamos un modelo de Hugging Face usando la clase `InferenceClientModel` - Creamos nuestro agente (Alfred) como un `CodeAgent`, que puede ejecutar código Python para resolver problemas - Le pedimos a Alfred que recupere información sobre una invitada llamada "Lady Ada Lovelace" ```python from llama_index.core.agent.workflow import AgentWorkflow from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI # Inicializar el modelo de Hugging Face llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") # Crear a Alfred, nuestro agente de gala, con la herramienta de información de invitados alfred = AgentWorkflow.from_tools_or_functions( [guest_info_tool], llm=llm, ) # Ejemplo de consulta que Alfred podría recibir durante la gala response = await alfred.run("Cuéntame sobre nuestra invitada llamada 'Lady Ada Lovelace'.") print("🎩 Respuesta de Alfred:") print(response) ``` Salida esperada: ``` 🎩 Respuesta de Alfred: Lady Ada Lovelace es una estimada matemática y amiga, reconocida por su trabajo pionero en matemáticas e informática. Es celebrada como la primera programadora de computadoras debido a su trabajo en la Máquina Analítica de Charles Babbage. Su correo electrónico es ada.lovelace@example.com. ``` Lo que está sucediendo en este paso final: - Inicializamos un modelo de Hugging Face usando la clase `HuggingFaceInferenceAPI` - Creamos nuestro agente (Alfred) como un `AgentWorkflow`, incluyendo la herramienta que acabamos de crear - Le pedimos a Alfred que recupere información sobre una invitada llamada "Lady Ada Lovelace" ```python from typing import TypedDict, Annotated from langgraph.graph.message import add_messages from langchain_core.messages import AnyMessage, HumanMessage, AIMessage from langgraph.prebuilt import ToolNode from langgraph.graph import START, StateGraph from langgraph.prebuilt import tools_condition from langchain_huggingface import HuggingFaceEndpoint, ChatHuggingFace # Generar la interfaz de chat, incluyendo las herramientas llm = HuggingFaceEndpoint( repo_id="Qwen/Qwen2.5-Coder-32B-Instruct", huggingfacehub_api_token=HUGGINGFACEHUB_API_TOKEN, ) chat = ChatHuggingFace(llm=llm, verbose=True) tools = [guest_info_tool] chat_with_tools = chat.bind_tools(tools) # Generar el AgentState y el grafo del Agente class AgentState(TypedDict): messages: Annotated[list[AnyMessage], add_messages] def assistant(state: AgentState): return { "messages": [chat_with_tools.invoke(state["messages"])], } ## El grafo builder = StateGraph(AgentState) # Definir nodos: estos hacen el trabajo builder.add_node("assistant", assistant) builder.add_node("tools", ToolNode(tools)) # Definir bordes: estos determinan cómo se mueve el flujo de control builder.add_edge(START, "assistant") builder.add_conditional_edges( "assistant", # Si el último mensaje requiere una herramienta, enrutar a herramientas # De lo contrario, proporcionar una respuesta directa tools_condition, ) builder.add_edge("tools", "assistant") alfred = builder.compile() messages = [HumanMessage(content="Cuéntame sobre nuestra invitada llamada 'Lady Ada Lovelace'.")] response = alfred.invoke({"messages": messages}) print("🎩 Respuesta de Alfred:") print(messages['messages'][-1].content) ``` Salida esperada: ``` 🎩 Respuesta de Alfred: Lady Ada Lovelace es una estimada matemática y pionera en informática, a menudo celebrada como la primera programadora de computadoras debido a su trabajo en la Máquina Analítica de Charles Babbage. ``` Lo que está sucediendo en este paso final: - Inicializamos un modelo de Hugging Face usando la clase `HuggingFaceEndpoint`. También generamos una interfaz de chat y añadimos las herramientas. - Creamos nuestro agente (Alfred) como un `StateGraph`, que combina 2 nodos (`assistant`, `tools`) usando un borde - Le pedimos a Alfred que recupere información sobre una invitada llamada "Lady Ada Lovelace" ## Ejemplo de Interacción Durante la gala, una conversación podría fluir así: **Tú:** "Alfred, ¿quién es ese caballero hablando con el embajador?" **Alfred:** *rápidamente busca en la base de datos de invitados* "Ese es el Dr. Nikola Tesla, señor. Es un viejo amigo de sus días universitarios. Recientemente ha patentado un nuevo sistema de transmisión de energía inalámbrica y estaría encantado de discutirlo con usted. Solo recuerde que es apasionado por las palomas, así que eso podría ser un buen tema de conversación." ```json { "name": "Dr. Nikola Tesla", "relation": "viejo amigo de días universitarios", "description": "El Dr. Nikola Tesla es un viejo amigo de sus días universitarios. Recientemente ha patentado un nuevo sistema de transmisión de energía inalámbrica y estaría encantado de discutirlo con usted. Solo recuerde que es apasionado por las palomas, así que eso podría ser un buen tema de conversación.", "email": "nikola.tesla@gmail.com" } ``` ## Llevándolo Más Allá Ahora que Alfred puede recuperar información de invitados, considera cómo podrías mejorar este sistema: 1. **Mejorar el recuperador** para usar un algoritmo más sofisticado como [sentence-transformers](https://www.sbert.net/) 2. **Implementar una memoria de conversación** para que Alfred recuerde interacciones previas 3. **Combinar con búsqueda web** para obtener la información más reciente sobre invitados desconocidos 4. **Integrar múltiples índices** para obtener información más completa de fuentes verificadas ¡Ahora Alfred está completamente equipado para manejar consultas de invitados sin esfuerzo, asegurando que tu gala sea recordada como el evento más sofisticado y encantador del siglo! > [!TIP] > Intenta extender la herramienta de recuperación para que también devuelva iniciadores de conversación basados en los intereses o antecedentes de cada invitado. ¿Cómo modificarías la herramienta para lograr esto? > > Cuando hayas terminado, implementa tu herramienta de recuperación de invitados en el archivo retriever.py. ================================================ FILE: units/es/unit3/agentic-rag/tools.mdx ================================================ # Construyendo e Integrando Herramientas para Tu Agente En esta sección, le daremos a Alfred acceso a la web, permitiéndole encontrar las últimas noticias y actualizaciones globales. Además, tendrá acceso a datos meteorológicos y estadísticas de descargas de modelos de Hugging Face Hub, para que pueda mantener conversaciones relevantes sobre temas actuales. ## Dale a Tu Agente Acceso a la Web Recuerda que queremos que Alfred establezca su presencia como un verdadero anfitrión renacentista, con un profundo conocimiento del mundo. Para lograrlo, necesitamos asegurarnos de que Alfred tenga acceso a las últimas noticias e información sobre el mundo. ¡Comencemos creando una herramienta de búsqueda web para Alfred! ```python from smolagents import DuckDuckGoSearchTool # Inicializar la herramienta de búsqueda DuckDuckGo search_tool = DuckDuckGoSearchTool() # Ejemplo de uso results = search_tool("¿Quién es el actual Presidente de Francia?") print(results) ``` Salida esperada: ``` The current President of France in Emmanuel Macron. ``` ```python from llama_index.tools.duckduckgo import DuckDuckGoSearchToolSpec from llama_index.core.tools import FunctionTool # Inicializar la herramienta de búsqueda DuckDuckGo tool_spec = DuckDuckGoSearchToolSpec() search_tool = FunctionTool.from_defaults(tool_spec.duckduckgo_full_search) # Ejemplo de uso response = search_tool("¿Quién es el actual Presidente de Francia?") print(response.raw_output[-1]['body']) ``` Expected output: ``` El Presidente de la República Francesa es el jefe de estado de Francia. El actual Presidente es Emmanuel Macron desde el 14 de mayo de 2017 tras derrotar a Marine Le Pen en la segunda vuelta de las elecciones presidenciales el 7 de mayo de 2017. Lista de Presidentes franceses (Quinta República) N° Nombre ... ``` ```python from langchain_community.tools import DuckDuckGoSearchRun search_tool = DuckDuckGoSearchRun() results = search_tool.invoke("¿Quién es el actual Presidente de Francia?") print(results) ``` Salida esperada: ``` Emmanuel Macron (born December 21, 1977, Amiens, France) is a French banker and politician who was elected president of France in 2017... ``` ## Creando una Herramienta Personalizada para Información Meteorológica para Programar los Fuegos Artificiales La gala perfecta tendría fuegos artificiales bajo un cielo despejado, necesitamos asegurarnos de que los fuegos artificiales no sean cancelados debido al mal tiempo. Vamos a crear una herramienta personalizada que pueda usarse para llamar a una API meteorológica externa y obtener la información del clima para una ubicación determinada. > [!TIP] > Por simplicidad, estamos usando una API meteorológica ficticia para este ejemplo. Si quieres usar una API meteorológica real, podrías implementar una herramienta meteorológica que use la API de OpenWeatherMap, como en la Unidad 1. ```python from smolagents import Tool import random class WeatherInfoTool(Tool): name = "weather_info" description = "Obtiene información meteorológica ficticia para una ubicación dada." inputs = { "location": { "type": "string", "description": "La ubicación para la que obtener información meteorológica." } } output_type = "string" def forward(self, location: str): # Datos meteorológicos ficticios weather_conditions = [ {"condition": "Lluvioso", "temp_c": 15}, {"condition": "Despejado", "temp_c": 25}, {"condition": "Ventoso", "temp_c": 20} ] # Seleccionar aleatoriamente una condición meteorológica data = random.choice(weather_conditions) return f"Clima en {location}: {data['condition']}, {data['temp_c']}°C" # Inicializar la herramienta weather_info_tool = WeatherInfoTool() ``` ```python import random from llama_index.core.tools import FunctionTool def get_weather_info(location: str) -> str: """Obtiene información meteorológica ficticia para una ubicación dada.""" # Datos meteorológicos ficticios weather_conditions = [ {"condition": "Lluvioso", "temp_c": 15}, {"condition": "Despejado", "temp_c": 25}, {"condition": "Ventoso", "temp_c": 20} ] # Seleccionar aleatoriamente una condición meteorológica data = random.choice(weather_conditions) return f"Clima en {location}: {data['condition']}, {data['temp_c']}°C" # Inicializar la herramienta weather_info_tool = FunctionTool.from_defaults(get_weather_info) ``` ```python from langchain_core.tools import Tool import random def get_weather_info(location: str) -> str: """Obtiene información meteorológica ficticia para una ubicación dada.""" # Datos meteorológicos ficticios weather_conditions = [ {"condition": "Lluvioso", "temp_c": 15}, {"condition": "Despejado", "temp_c": 25}, {"condition": "Ventoso", "temp_c": 20} ] # Seleccionar aleatoriamente una condición meteorológica data = random.choice(weather_conditions) return f"Clima en {location}: {data['condition']}, {data['temp_c']}°C" # Inicializar la herramienta weather_info_tool = Tool( name="get_weather_info", func=get_weather_info, description="Obtiene información meteorológica ficticia para una ubicación dada." ) ``` ## Creando una Herramienta de Estadísticas de Hub para Influyentes Creadores de IA Entre los asistentes a la gala están los más destacados creadores de IA. Alfred quiere impresionarlos discutiendo sus modelos, conjuntos de datos y espacios más populares. Crearemos una herramienta para obtener estadísticas de modelos desde Hugging Face Hub basadas en un nombre de usuario. ```python from smolagents import Tool from huggingface_hub import list_models class HubStatsTool(Tool): name = "hub_stats" description = "Obtiene el modelo más descargado de un autor específico en Hugging Face Hub." inputs = { "author": { "type": "string", "description": "El nombre de usuario del autor/organización del modelo para encontrar modelos." } } output_type = "string" def forward(self, author: str): try: # Listar modelos del autor especificado, ordenados por descargas models = list(list_models(author=author, sort="downloads", direction=-1, limit=1)) if models: model = models[0] return f"El modelo más descargado de {author} es {model.id} con {model.downloads:,} descargas." else: return f"No se encontraron modelos para el autor {author}." except Exception as e: return f"Error al obtener modelos para {author}: {str(e)}" # Inicializar la herramienta hub_stats_tool = HubStatsTool() # Ejemplo de uso print(hub_stats_tool("facebook")) # Ejemplo: Obtener el modelo más descargado de Facebook ``` Salida esperada: ``` The most downloaded model by facebook is facebook/esmfold_v1 with 12,544,550 downloads. ``` ```python import random from llama_index.core.tools import FunctionTool from huggingface_hub import list_models def get_hub_stats(author: str) -> str: """Obtiene el modelo más descargado de un autor específico en Hugging Face Hub.""" try: # Listar modelos del autor especificado, ordenados por descargas models = list(list_models(author=author, sort="downloads", direction=-1, limit=1)) if models: model = models[0] return f"El modelo más descargado de {author} es {model.id} con {model.downloads:,} descargas." else: return f"No se encontraron modelos para el autor {author}." except Exception as e: return f"Error al obtener modelos para {author}: {str(e)}" # Inicializar la herramienta hub_stats_tool = FunctionTool.from_defaults(get_hub_stats) # Ejemplo de uso print(hub_stats_tool("facebook")) # Ejemplo: Obtener el modelo más descargado de Facebook ``` Salida esperada: ``` The most downloaded model by facebook is facebook/esmfold_v1 with 12,544,550 downloads. ``` ```python from langchain_core.tools import Tool from huggingface_hub import list_models def get_hub_stats(author: str) -> str: """Obtiene el modelo más descargado de un autor específico en Hugging Face Hub.""" try: # Listar modelos del autor especificado, ordenados por descargas models = list(list_models(author=author, sort="downloads", direction=-1, limit=1)) if models: model = models[0] return f"El modelo más descargado de {author} es {model.id} con {model.downloads:,} descargas." else: return f"No se encontraron modelos para el autor {author}." except Exception as e: return f"Error al obtener modelos para {author}: {str(e)}" # Inicializar la herramienta hub_stats_tool = Tool( name="get_hub_stats", func=get_hub_stats, description="Obtiene el modelo más descargado de un autor específico en Hugging Face Hub." ) # Ejemplo de uso print(hub_stats_tool.invoke("facebook")) # Ejemplo: Obtener el modelo más descargado de Facebook ``` Salida esperada: ``` The most downloaded model by facebook is facebook/esmfold_v1 with 13,109,861 downloads. ``` Con la Herramienta de Estadísticas de Hub, Alfred ahora puede impresionar a influyentes creadores de IA discutiendo sus modelos más populares. ## Integrando Herramientas con Alfred Ahora que tenemos todas las herramientas, vamos a integrarlas en el agente de Alfred: ```python from smolagents import CodeAgent, InferenceClientModel # Inicializar el modelo de Hugging Face model = InferenceClientModel() # Crear Alfred con todas las herramientas alfred = CodeAgent( tools=[search_tool, weather_info_tool, hub_stats_tool], model=model ) # Ejemplo de consulta que Alfred podría recibir durante la gala response = alfred.run("¿Qué es Facebook y cuál es su modelo más popular?") print("🎩 Respuesta de Alfred:") print(response) ``` Salida esperada: ``` 🎩 Respuesta de Alfred: Facebook es un sitio web de redes sociales donde los usuarios pueden conectarse, compartir información e interactuar con otros. El modelo más descargado de Facebook en Hugging Face Hub es ESMFold_v1. ``` ```python from llama_index.core.agent.workflow import AgentWorkflow from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI # Inicializar el modelo de Hugging Face llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") # Crear Alfred con todas las herramientas alfred = AgentWorkflow.from_tools_or_functions( [search_tool, weather_info_tool, hub_stats_tool], llm=llm ) # Ejemplo de consulta que Alfred podría recibir durante la gala response = await alfred.run("¿Qué es Facebook y cuál es su modelo más popular?") print("🎩 Respuesta de Alfred:") print(response) ``` Salida esperada: ``` 🎩 Respuesta de Alfred: Facebook es un servicio de redes sociales y una empresa tecnológica con sede en Menlo Park, California. Fue fundada por Mark Zuckerberg y permite a las personas crear perfiles, conectarse con amigos y familiares, compartir fotos y videos, y unirse a grupos basados en intereses compartidos. El modelo más popular de Facebook en Hugging Face Hub es `facebook/esmfold_v1` con 13,109,861 descargas. ``` ```python from typing import TypedDict, Annotated from langgraph.graph.message import add_messages from langchain_core.messages import AnyMessage, HumanMessage, AIMessage from langgraph.prebuilt import ToolNode from langgraph.graph import START, StateGraph from langgraph.prebuilt import tools_condition from langchain_huggingface import HuggingFaceEndpoint, ChatHuggingFace # Generar la interfaz de chat, incluyendo las herramientas llm = HuggingFaceEndpoint( repo_id="Qwen/Qwen2.5-Coder-32B-Instruct", huggingfacehub_api_token=HUGGINGFACEHUB_API_TOKEN, ) chat = ChatHuggingFace(llm=llm, verbose=True) tools = [search_tool, weather_info_tool, hub_stats_tool] chat_with_tools = chat.bind_tools(tools) # Generar el AgentState y el grafo del Agente class AgentState(TypedDict): messages: Annotated[list[AnyMessage], add_messages] def assistant(state: AgentState): return { "messages": [chat_with_tools.invoke(state["messages"])], } ## El grafo builder = StateGraph(AgentState) # Definir nodos: estos hacen el trabajo builder.add_node("assistant", assistant) builder.add_node("tools", ToolNode(tools)) # Definir bordes: estos determinan cómo se mueve el flujo de control builder.add_edge(START, "assistant") builder.add_conditional_edges( "assistant", # Si el último mensaje requiere una herramienta, enrutar a herramientas # De lo contrario, proporcionar una respuesta directa tools_condition, ) builder.add_edge("tools", "assistant") alfred = builder.compile() messages = [HumanMessage(content="¿Quién es Facebook y cuál es su modelo más popular?")] response = alfred.invoke({"messages": messages}) print("🎩 Respuesta de Alfred:") print(response['messages'][-1].content) ``` Salida esperada: ``` 🎩 Respuesta de Alfred: Facebook es una empresa de redes sociales conocida por su sitio de redes sociales, Facebook, así como otros servicios como Instagram y WhatsApp. El modelo más descargado de Facebook en Hugging Face Hub es facebook/esmfold_v1 con 13,202,321 descargas. ``` ## Conclusión Al integrar estas herramientas, Alfred ahora está equipado para manejar una variedad de tareas, desde búsquedas web hasta actualizaciones meteorológicas y estadísticas de modelos. Esto asegura que se mantenga como el anfitrión más informado y atractivo en la gala. > [!TIP] > Intenta implementar una herramienta que pueda usarse para obtener las últimas noticias sobre un tema específico. > > Cuando hayas terminado, implementa tus herramientas personalizadas en el archivo tools.py. ================================================ FILE: units/es/unit4/README.md ================================================ ================================================ FILE: units/es/unit4/additional-readings.mdx ================================================ # ¿Y ahora? ¿Qué temas debería aprender? La IA Agéntica es un campo en rápida evolución, y comprender los protocolos fundamentales es esencial para construir sistemas inteligentes y autónomos. Dos estándares importantes con los que deberías familiarizarte son: - El **Protocolo de Contexto del Modelo (MCP)** - El **Protocolo Agente a Agente (A2A)** ## 🔌 Protocolo de Contexto del Modelo (MCP) El **Protocolo de Contexto del Modelo (MCP)** de Anthropic es un estándar abierto que permite a los modelos de IA **conectarse de forma segura y fluida con herramientas externas, fuentes de datos y aplicaciones**, haciendo que los agentes sean más capaces y autónomos. Piensa en el MCP como un **adaptador universal**, como un puerto USB-C, que permite a los modelos de IA conectarse a diversos entornos digitales **sin necesidad de una integración personalizada para cada uno**. El MCP está ganando rápidamente terreno en la industria, con grandes empresas como OpenAI y Google comenzando a adoptarlo. 📚 Aprende más: - [Anuncio oficial y documentación de Anthropic](https://www.anthropic.com/news/model-context-protocol) - [MCP en Wikipedia (en inglés)](https://en.wikipedia.org/wiki/Model_Context_Protocol) - [Blog sobre MCP (en inglés)](https://huggingface.co/blog/Kseniase/mcp) ## 🤝 Protocolo Agente a Agente (A2A) Google ha desarrollado el **Protocolo Agente a Agente (A2A)** como contraparte complementaria al Protocolo de Contexto del Modelo (MCP) de Anthropic. Mientras que el MCP conecta a los agentes con herramientas externas, **el A2A conecta a los agentes entre sí**, allanando el camino para sistemas cooperativos multiagente que pueden trabajar juntos para resolver problemas complejos. 📚 Profundiza en A2A: - [Anuncio de A2A de Google (en inglés)](https://developers.googleblog.com/en/a2a-a-new-era-of-agent-interoperability/) ================================================ FILE: units/es/unit4/conclusion.mdx ================================================ # Conclusión **¡Felicitaciones por terminar el Curso de Agentes!** A través de la perseverancia y la dedicación, has construido una base sólida en el mundo de los Agentes de IA. Pero terminar este curso **no es el final de tu viaje**. Es solo el comienzo: no dudes en explorar la siguiente sección donde compartimos recursos seleccionados para ayudarte a continuar aprendiendo, incluyendo temas avanzados como los **MCP** y más allá. **Gracias** por ser parte de este curso. **Esperamos que te haya gustado tanto como a nosotros nos encantó escribirlo**. Y no lo olvides: **Sigue Aprendiendo, Mantente Genial 🤗** ================================================ FILE: units/es/unit4/get-your-certificate.mdx ================================================ # Reclama tu Certificado 🎓 Si obtuviste una puntuación **superior al 30%, ¡felicitaciones! 👏 Ahora eres elegible para reclamar tu certificado oficial.** Sigue los pasos a continuación para recibirlo: 1. Visita la [página del certificado](https://huggingface.co/spaces/agents-course/Unit4-Final-Certificate). 2. **Inicia sesión** con tu cuenta de Hugging Face usando el botón proporcionado. 3. **Ingresa tu nombre completo**. Este es el nombre que aparecerá en tu certificado. 4. Haz clic en **“Obtener Mi Certificado”** para verificar tu puntuación y descargar tu certificado. ¡Felicidades! Una vez que tengas tu certificado, siéntete libre de: - Agregarlo a tu **perfil de LinkedIn** 🧑‍💼 - Compartirlo en **X**, **Bluesky**, etc. 🎉 **No olvides etiquetar a [@huggingface](https://huggingface.co/huggingface). ¡Estaremos súper orgullosos y nos encantaría animarte! 🤗** ================================================ FILE: units/es/unit4/hands-on.mdx ================================================ # Práctica Ahora que estás listo/a para profundizar en la creación de tu agente final, veamos cómo puedes enviarlo para su revisión. ## El Conjunto de Datos (Dataset) El conjunto de datos utilizado en esta tabla de clasificación consta de 20 preguntas extraídas de las preguntas de nivel 1 del conjunto de **validación** de GAIA. Las preguntas elegidas se filtraron según la cantidad de herramientas y pasos necesarios para responder una pregunta. Basándonos en el estado actual del benchmark GAIA, creemos que intentar alcanzar un 30% en las preguntas de nivel 1 es una prueba justa. ¡Estado actual de GAIA! ## El Proceso Ahora, la gran pregunta en tu mente probablemente sea: "¿Cómo empiezo a enviar?" Para esta Unidad, creamos una API que te permitirá obtener las preguntas y enviar tus respuestas para su puntuación. Aquí tienes un resumen de las rutas (consulta la [documentación en vivo](https://agents-course-unit4-scoring.hf.space/docs) para detalles interactivos): * **`GET /questions`**: Recupera la lista completa de preguntas de evaluación filtradas. * **`GET /random-question`**: Obtiene una única pregunta aleatoria de la lista. * **`GET /files/{task_id}`**: Descarga un archivo específico asociado con un ID de tarea determinado. * **`POST /submit`**: Envía las respuestas del agente, calcula la puntuación y actualiza la tabla de clasificación. La función de envío comparará la respuesta con la verdad fundamental (ground truth) de manera de **COINCIDENCIA EXACTA** (exact match), ¡así que dale un buen prompt! El equipo de GAIA compartió un ejemplo de prompting para tu agente [aquí](https://huggingface.co/spaces/gaia-benchmark/leaderboard). 🎨 **¡Haz Tuya la Plantilla!** Para demostrar el proceso de interacción con la API, hemos incluido una [plantilla básica](https://huggingface.co/spaces/agents-course/Final_Assignment_Template) como punto de partida. Por favor, siéntete libre —y te **animamos activamente**— a cambiarla, agregarle elementos o reestructurarla por completo. Modifícala de cualquier manera que se adapte mejor a tu enfoque y creatividad. Para enviar usando esta plantilla, calcula 3 cosas necesarias para la API: * **Nombre de usuario (`Username`):** Tu nombre de usuario de Hugging Face (aquí obtenido mediante el inicio de sesión de Gradio), que se utiliza para identificar tu envío. * **Enlace al Código (`agent_code`):** La URL que enlaza al código de tu Space de Hugging Face (`.../tree/main`) para fines de verificación, así que por favor mantén tu Space público. * **Respuestas (`answers`):** La lista de respuestas (`{"task_id": ..., "submitted_answer": ...}`) generadas por tu Agente para la puntuación. Por lo tanto, te animamos a comenzar duplicando esta [plantilla](https://huggingface.co/spaces/agents-course/Final_Assignment_Template) en tu propio perfil de Hugging Face. 🏆 Revisa la tabla de clasificación [aquí](https://huggingface.co/spaces/agents-course/Students_leaderboard) *Nota amistosa: ¡Esta tabla de clasificación es por diversión! Sabemos que es posible enviar puntuaciones sin una verificación completa. Si vemos demasiadas puntuaciones altas publicadas sin un enlace público que las respalde, es posible que necesitemos revisar, ajustar o eliminar algunas entradas para mantener la tabla de clasificación útil.* La tabla de clasificación mostrará el enlace a la base de código de tu Space; dado que esta tabla es solo para estudiantes, por favor mantén tu Space público si obtienes una puntuación de la que estés orgulloso/a. ================================================ FILE: units/es/unit4/introduction.mdx ================================================ # Bienvenido/a a la última Unidad [[introduccion]] Miniatura Curso Agentes IA ¡Bienvenido/a a la última unidad del curso! 🎉 Hasta ahora, has **construido una base sólida en Agentes de IA**, desde comprender sus componentes hasta crear los tuyos propios. Con este conocimiento, ahora estás listo/a para **construir agentes poderosos** y mantenerte al día con los últimos avances en este campo en rápida evolución. Esta unidad trata sobre aplicar lo que has aprendido. Es tu **proyecto práctico final**, y completarlo es tu boleto para obtener el **certificado del curso**. ## ¿Cuál es el desafío? Crearás tu propio agente y **evaluarás su rendimiento utilizando un subconjunto del [benchmark GAIA](https://huggingface.co/spaces/gaia-benchmark/leaderboard)**. Para completar con éxito el curso, tu agente necesita obtener una puntuación del **30% o superior** en el benchmark. Logra eso, y obtendrás tu **Certificado de Finalización**, reconociendo oficialmente tu experiencia. 🏅 ¡Además, mira cómo te comparas con tus compañeros! Una **[Tabla de Clasificación de Estudiantes](https://huggingface.co/spaces/agents-course/Students_leaderboard)** dedicada está disponible para que envíes tus puntuaciones y veas el progreso de la comunidad. > ** 🚨 Atención: Unidad Avanzada y Práctica** > > Ten en cuenta que esta unidad cambia hacia un enfoque más práctico. El éxito en esta sección requerirá **conocimientos de codificación más avanzados** y depende de que navegues por las tareas con **menos guía explícita** en comparación con las partes anteriores del curso. ¿Suena emocionante? ¡Comencemos! 🚀 ================================================ FILE: units/es/unit4/what-is-gaia.mdx ================================================ # ¿Qué es GAIA? [GAIA](https://huggingface.co/papers/2311.12983) es un **benchmark diseñado para evaluar asistentes de IA en tareas del mundo real** que requieren una combinación de capacidades centrales, como razonamiento, comprensión multimodal, navegación web y uso competente de herramientas. Fue introducido en el artículo _"[GAIA: A Benchmark for General AI Assistants](https://huggingface.co/papers/2311.12983) (en inglés)"_. El benchmark presenta **466 preguntas cuidadosamente seleccionadas** que son **conceptualmente simples para los humanos**, pero **notablemente desafiantes para los sistemas de IA actuales**. Para ilustrar la brecha: - **Humanos**: Tasa de éxito de ~92% - **GPT-4 con plugins**: ~15% - **Deep Research (OpenAI)**: 67.36% en el conjunto de validación GAIA destaca las limitaciones actuales de los modelos de IA y proporciona un benchmark riguroso para evaluar el progreso hacia asistentes de IA verdaderamente de propósito general. ## 🌱 Principios Fundamentales de GAIA GAIA está cuidadosamente diseñado en torno a los siguientes pilares: - 🔍 **Dificultad del mundo real**: Las tareas requieren razonamiento de varios pasos, comprensión multimodal e interacción con herramientas. - 🧾 **Interpretabilidad humana**: A pesar de su dificultad para la IA, las tareas siguen siendo conceptualmente simples y fáciles de seguir para los humanos. - 🛡️ **No manipulable (Non-gameability)**: Las respuestas correctas exigen la ejecución completa de la tarea, lo que hace ineficaz el forzamiento bruto (brute-forcing). - 🧰 **Simplicidad de evaluación**: Las respuestas son concisas, factuales y sin ambigüedades, ideales para el benchmarking. ## Niveles de Dificultad Las tareas de GAIA se organizan en **tres niveles de complejidad creciente**, cada uno probando habilidades específicas: - **Nivel 1**: Requiere menos de 5 pasos y un uso mínimo de herramientas. - **Nivel 2**: Implica un razonamiento más complejo y la coordinación entre múltiples herramientas y 5-10 pasos. - **Nivel 3**: Exige planificación a largo plazo e integración avanzada de diversas herramientas. ![Niveles de GAIA](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit4/gaia_levels.png) ## Ejemplo de una Pregunta Difícil de GAIA > ¿Cuáles de las frutas mostradas en la pintura de 2008 "Bordado de Uzbekistán" se sirvieron como parte del menú de desayuno de octubre de 1949 para el transatlántico que luego se usó como utilería flotante para la película "El último viaje"? Enumera los elementos como una lista separada por comas, ordenándolos en el sentido de las agujas del reloj según su disposición en la pintura, comenzando desde la posición de las 12 en punto. Usa la forma plural de cada fruta. Como puedes ver, esta pregunta desafía a los sistemas de IA de varias maneras: - Requiere un **formato de respuesta estructurado** - Implica **razonamiento multimodal** (por ejemplo, analizar imágenes) - Exige **recuperación de múltiples saltos** (multi-hop retrieval) de hechos interdependientes: - Identificar las frutas en la pintura - Descubrir qué transatlántico se usó en *El último viaje* - Buscar el menú de desayuno de octubre de 1949 para ese barco - Necesita **secuenciación correcta** y planificación de alto nivel para resolver en el orden correcto Este tipo de tarea resalta dónde los LLM independientes a menudo se quedan cortos, lo que convierte a GAIA en un benchmark ideal para **sistemas basados en agentes** que pueden razonar, recuperar y ejecutar a lo largo de múltiples pasos y modalidades. ![Gráfico de capacidades de GAIA](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit4/gaia_capabilities.png) ## Evaluación en Vivo Para fomentar el benchmarking continuo, **GAIA proporciona una tabla de clasificación pública alojada en Hugging Face**, donde puedes probar tus modelos contra **300 preguntas de prueba**. 👉 Revisa la tabla de clasificación [aquí](https://huggingface.co/spaces/gaia-benchmark/leaderboard) ¿Quieres profundizar más en GAIA? - 📄 [Lee el artículo completo (en inglés)](https://huggingface.co/papers/2311.12983) - 📄 [Publicación de lanzamiento de Deep Research por OpenAI (en inglés)](https://openai.com/index/introducing-deep-research/) - 📄 [DeepResearch de código abierto – Liberando nuestros agentes de búsqueda (en inglés)](https://huggingface.co/blog/open-deep-research) ================================================ FILE: units/fr/_toctree.yml ================================================ - title: Unité 0. Bienvenue dans le cours sections: - local: unit0/introduction title: Bienvenue dans le cours 🤗 - local: unit0/onboarding title: Embarquement - local: unit0/discord101 title: (Optionnel) Introduction à Discord - title: Live 1. Comment fonctionne le cours et Q&R sections: - local: communication/live1 title: Live 1. Comment fonctionne le cours et Q&R - title: Unité 1. Introduction aux Agents sections: - local: unit1/introduction title: Introduction aux agents - local: unit1/what-are-agents title: Qu'est-ce qu'un agent ? - local: unit1/quiz1 title: Quiz rapide 1 - local: unit1/what-are-llms title: Qu'est-ce qu'un LLM ? - local: unit1/messages-and-special-tokens title: Messages et tokens spéciaux - local: unit1/tools title: Que sont les outils ? - local: unit1/quiz2 title: Quiz rapide 2 - local: unit1/agent-steps-and-structure title: Comprendre les agents à travers le cycle Réflexion-Action-Observation - local: unit1/thoughts title: Réflexions, raisonnement interne et l'approche Re-Act - local: unit1/actions title: Actions, permettre à l'agent d'interagir avec son environnement - local: unit1/observations title: Observer, intégrer le retour d'information pour réfléchir et s'adapter - local: unit1/dummy-agent-library title: Bibliothèque d'agents factices - local: unit1/tutorial title: Créons notre premier agent avec smolagents - local: unit1/final-quiz title: Quiz final de l'Unité 1 - local: unit1/conclusion title: Conclusion - title: Unité 2. Frameworks pour les agents sections: - local: unit2/introduction title: Frameworks pour les agents - title: Unité 2.1 Le framework smolagents sections: - local: unit2/smolagents/introduction title: Introduction à smolagents - local: unit2/smolagents/why_use_smolagents title: Pourquoi utiliser smolagents ? - local: unit2/smolagents/quiz1 title: Quiz rapide 1 - local: unit2/smolagents/code_agents title: Construire des agents qui utilisent du code - local: unit2/smolagents/tool_calling_agents title: Écrire des actions sous forme d'extraits de code ou de blobs JSON - local: unit2/smolagents/tools title: Outils - local: unit2/smolagents/retrieval_agents title: Construction de systèmes de RAG agentiques - local: unit2/smolagents/quiz2 title: Quiz rapide 2 - local: unit2/smolagents/multi_agent_systems title: Systèmes multi-agents - local: unit2/smolagents/vision_agents title: Agents visuel avec smolagents - local: unit2/smolagents/final_quiz title: Quiz final - local: unit2/smolagents/conclusion title: Conclusion - title: Unité 2.2 Le framework LlamaIndex sections: - local: unit2/llama-index/introduction title: Introduction à LlamaIndex - local: unit2/llama-index/llama-hub title: Introduction au LlamaHub - local: unit2/llama-index/components title: Que sont les components dans LlamaIndex ? - local: unit2/llama-index/tools title: Utiliser des outils dans LlamaIndex - local: unit2/llama-index/quiz1 title: Quiz rapide 1 - local: unit2/llama-index/agents title: Utiliser des agents dans LlamaIndex - local: unit2/llama-index/workflows title: Créer des workflows agentiques dans LlamaIndex - local: unit2/llama-index/quiz2 title: Quiz rapide 2 - local: unit2/llama-index/conclusion title: Conclusion - title: Unité 2.3 Le framework LangGraph sections: - local: unit2/langgraph/introduction title: Introduction à LangGraph - local: unit2/langgraph/when_to_use_langgraph title: Qu'est-ce que LangGraph ? - local: unit2/langgraph/building_blocks title: Les blocs de construction de LangGraph - local: unit2/langgraph/first_graph title: Construire votre premier LangGraph - local: unit2/langgraph/document_analysis_agent title: Graphe d'analyse de documents - local: unit2/langgraph/quiz1 title: Quiz rapide 1 - local: unit2/langgraph/conclusion title: Conclusion - title: Unité 3. Cas d'usage pour le RAG agentique sections: - local: unit3/agentic-rag/introduction title: Introduction au cas d'usage de RAG agentique - local: unit3/agentic-rag/agentic-rag title: RAG agentique - local: unit3/agentic-rag/invitees title: Création d'un RAG pour converser avec les invités - local: unit3/agentic-rag/tools title: Création et intégration d'outils pour votre agent - local: unit3/agentic-rag/agent title: Création de l'agent pour le gala - local: unit3/agentic-rag/conclusion title: Conclusion - title: Unité 4. Projet final - Créer, tester et certifier votre agent sections: - local: unit4/introduction title: Introduction à l'unité finale - local: unit4/what-is-gaia title: Qu'est-ce que GAIA ? - local: unit4/hands-on title: Le projet pratique final - local: unit4/get-your-certificate title: Obtenez votre certificat - local: unit4/conclusion title: Conclusion du cours - local: unit4/additional-readings title: Et maintenant ? Quels sujets devrais-je apprendre ? - title: Unité bonus 1. Affiner un LLM pour l'appel de fonctions sections: - local: bonus-unit1/introduction title: Introduction - local: bonus-unit1/what-is-function-calling title: Qu'est-ce que l'appel de fonctions ? - local: bonus-unit1/fine-tuning title: Finetunons un modèle pour pouvoir faire de l'appel de fonctions - local: bonus-unit1/conclusion title: Conclusion - title: Unité bonus 2. Observabilité et évaluation des agents sections: - local: bonus-unit2/introduction title: Introduction - local: bonus-unit2/what-is-agent-observability-and-evaluation title: Qu'est-ce que l'observabilité et l'évaluation des agents ? - local: bonus-unit2/monitoring-and-evaluating-agents-notebook title: Observer et évaluer des agents - local: bonus-unit2/quiz title: Quiz - title: Unité bonus 3. Agents dans les jeux avec Pokémon sections: - local: bonus-unit3/introduction title: Introduction - local: bonus-unit3/state-of-art title: L'état de l'art de l'utilisation des LLM dans les jeux - local: bonus-unit3/from-llm-to-agents title: Des LLM aux agents - local: bonus-unit3/building_your_pokemon_agent title: Construire un agent de combat Pokémon - local: bonus-unit3/launching_agent_battle title: Lancer l'agent de combat Pokémon - local: bonus-unit3/conclusion title: Conclusion ================================================ FILE: units/fr/bonus-unit1/conclusion.mdx ================================================ # Conclusion [[conclusion]] Félicitations pour avoir terminé cette première Unité Bonus 🥳 Vous **maîtrisez la compréhension de l'appel de fonctions et comment finetuner votre modèle sur cette tâche** ! Nous vous conseillons à présent d'essayer de **finetuner différents modèles**. La **meilleure façon d'apprendre est en testant des choses.** Dans la prochaine Unité, vous allez apprendre comment utiliser **des *frameworks* de pointe tels que `smolagents`, `LlamaIndex` et `LangGraph`**. Enfin, nous serions ravis **d'entendre ce que vous pensez du cours et comment nous pourrions l'améliorer**. Si vous avez des retours, n'hésitez pas à 👉 [remplir ce formulaire](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog). ### Continuez à apprendre, restez géniaux 🤗 ================================================ FILE: units/fr/bonus-unit1/fine-tuning.mdx ================================================ # Finetunons un modèle pour pouvoir faire de l'appel de fonctions Nous sommes maintenant prêts à finetuner notre premier modèle pour de l'appel de fonctions 🔥. ## Comment entraînons-nous un tel modèle ? > Réponse : Nous avons besoin de **données** Un processus d'entraînement peut être divisé en 3 étapes : 1. **Le modèle est pré-entraîné sur une grande quantité de données**. Le résultat de cette étape est un **modèle pré-entraîné**. Par exemple, [google/gemma-2-2b](https://huggingface.co/google/gemma-2-2b). C'est un modèle de base et il sait seulement comment **prédire le prochain *token* sans fortes capacités de suivi d'instructions**. 2. Pour être utile dans un contexte de conversation, le modèle doit ensuite être **finetuné** pour suivre des instructions. À cette étape, il peut être entraîné par les créateurs du modèle, la communauté open-source, vous, ou n'importe qui. Par exemple, [google/gemma-2-2b-it](https://huggingface.co/google/gemma-2-2b-it) est un modèle finetuné pour les instructions par l'équipe Google derrière le projet Gemma. 3. Le modèle peut ensuite être **aligné** selon les préférences du créateur. Par exemple, un modèle conversationnel d'un service client ne doit jamais être impoli avec l'utilisateur. Habituellement, un produit complet comme *Gemini* ou *Mistral* **sera passé par les 3 étapes**, alors que les modèles que vous pouvez trouver sur *Hugging Face* ont effectué une ou plusieurs étapes de cet entraînement. Dans ce tutoriel, nous allons construire un modèle d'appel de fonctions basé sur [google/gemma-2-2b-it](https://huggingface.co/google/gemma-2-2b-it). Nous choisissons le modèle [google/gemma-2-2b-it](https://huggingface.co/google/gemma-2-2b-it) au lieu du modèle de base [google/gemma-2-2b](https://huggingface.co/google/gemma-2-2b) parce que le modèle finetuné a été amélioré pour notre cas d'usage. Partir du modèle pré-entraîné **nécessiterait plus d'entraînement pour apprendre le suivi d'instructions, le chat ET l'appel de fonctions**. En partant du modèle finetuné pour les instructions, **nous minimisons la quantité d'informations que notre modèle doit apprendre**. ## LoRA (Low-Rank Adaptation of Large Language Models) LoRA est une technique d'entraînement populaire et légère qui **réduit significativement le nombre de paramètres à entraîner**. Elle fonctionne en **insérant un lot d'adaptateurs constitués d'un petit nombre de nouveaux poids, dans le modèle à entraîner**. Cela rend l'entraînement avec LoRA beaucoup plus rapide, économe en mémoire, et produit des poids de modèle plus petits (quelques centaines de MB), qui sont plus faciles à stocker et partager. LoRA inference LoRA fonctionne en ajoutant des paires de matrices de décomposition de rang aux couches d'un *transformer* (typiquement les couches linéaires). Durant l'entraînement, nous gèlons le reste du modèle et ne mettons à jour uniquement les poids de ces adaptateurs ajoutés. Ce faisant, le nombre de **paramètres** que nous devons entraîner diminue considérablement car nous devons seulement mettre à jour les poids des adaptateurs. Durant l'inférence, l'entrée est passée dans les adaptateurs et le modèle de base. Ou bien les poids des adaptateurs peuvent être fusionnés avec le modèle de base, ne résultant en aucune surcharge de latence supplémentaire. LoRA est particulièrement utile pour adapter de **grands** modèles de langage à des tâches ou domaines spécifiques tout en gardant les exigences de ressources gérables. Cela aide à réduire la mémoire **requise** pour entraîner un modèle. Si vous voulez en savoir plus sur comment LoRA fonctionne, vous devriez consulter ce [tutoriel](https://huggingface.co/learn/nlp-course/chapter11/4?fw=pt). ## Finetuning d'un modèle pour l'appel de fonctions La suite de cette section se passe dans le *notebook* du tutoriel que vous pouvez accéder 👉 [ici](https://huggingface.co/agents-course/notebooks/blob/main/fr/bonus-unit1/bonus-unit1.ipynb). Ensuite, cliquez sur [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/#fileId=https://huggingface.co/agents-course/notebooks/blob/main/fr/bonus-unit1/bonus-unit1.ipynb) pour pouvoir l'exécuter dans Colab. ================================================ FILE: units/fr/bonus-unit1/introduction.mdx ================================================ # Introduction ![Bonus Unit 1 Thumbnail](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit1/thumbnail.jpg) Bienvenue dans cette première **Unité Bonus**, où vous apprendrez à **finetuner un LLM pour de l'appel de fonctions** (*function calling*). En termes de LLM, l'appel de fonctions devient rapidement une technique *incontournable*. L'idée est que, plutôt que de s'appuyer uniquement sur des approches basées sur des *prompts* comme nous l'avons fait dans l'Unité 1, l'appel de fonctions entraîne votre modèle à **prendre des actions et interpréter des observations pendant la phase d'entraînement**, rendant votre IA plus robuste. > **Quand dois-je faire cette Unité Bonus ?** > > Cette section est **optionnelle** et plus avancée que l'Unité 1, donc n'hésitez pas à faire cette unité maintenant ou à la revisiter quand vos connaissances se seront davantage développées grâce à ce cours. > > Mais ne vous inquiétez pas, cette Unité Bonus est conçue pour avoir toutes les informations dont vous avez besoin, donc nous vous guiderons à travers chaque concept central du finetuning d'un modèle d'appel de fonctions même si vous n'avez pas encore appris le fonctionnement interne de ce type de finetuning. La meilleure façon pour vous de pouvoir suivre cette Unité Bonus est de : 1. Savoir comment finetuner un modèle avec *Transformers*. Si ce n'est pas le cas [consultez cette page](https://huggingface.co/learn/nlp-course/fr/chapter3/1?fw=pt). 2. Savoir comment utiliser `SFTTrainer` de *TRL* pour finetuner un modèle. Pour en savoir plus à ce sujet [consultez cette documentation](https://huggingface.co/learn/nlp-course/en/chapter11/1). --- ## Ce que vous allez apprendre 1. **L'appel de fonctions** (*Function Calling*) Comment les LLM modernes structurent leurs conversations de manière efficace afin de déclencher des **outils**. 2. **LoRA** (*Low-Rank Adaptation*) Une méthode de finetuning **légère et efficace** qui réduit les coûts computationnels et de stockage. LoRA rend l'entraînement de gros modèles *plus rapide, moins cher et plus facile* à déployer. 3. **Le cycle Réflexion → Action → Observation** dans les modèles d'appel de fonctions Une approche simple mais puissante pour structurer comment votre modèle décide quand (et comment) appeler des fonctions, suivre les étapes intermédiaires et interpréter les résultats des outils ou APIs externes. 4. **De nouveaux *tokens* spéciaux** Nous introduirons des **marqueurs spéciaux** qui aident le modèle à distinguer entre : - Le raisonnement interne "*chain-of-thought*" - Les appels de fonctions sortants - Les réponses provenant d'outils externes --- À la fin de cette unité bonus, vous serez capable de : - **Comprendre** le fonctionnement interne des APIs quand il s'agit d'outils. - **Finetuner** un modèle en utilisant la technique LoRA. - **Implémenter** et **modifier** le cycle Réflexion → Action → Observation pour créer des *workflow* d'appel de fonctions robustes et maintenables. - **Concevoir et utiliser** des *tokens* spéciaux pour séparer de manière transparente le raisonnement interne du modèle de ses actions externes. Et vous **aurez finetuné votre propre modèle pour faire de l'appel de fonctions.** 🔥 Plongeons dans **l'appel de fonctions** ! ================================================ FILE: units/fr/bonus-unit1/what-is-function-calling.mdx ================================================ # Qu'est-ce que l'appel de fonctions ? Tout comme les outils, l'appel de fonctions (*function-calling*) est une **façon pour un LLM de prendre des actions basé sur son environnement**. Cependant, la capacité d'appel de fonctions **est apprise par le modèle**, et repose **moins sur le *prompting* que d'autres techniques d'agents**. Cette approche a d'abord été [introduite dans GPT-4](https://openai.com/index/function-calling-and-other-api-updates/), et a ensuite été reproduite dans d'autres modèles. Durant l'Unité 1, l'agent **n'a pas appris à utiliser les outils**. Nous avons juste fourni une liste, et nous nous sommes appuyés sur le fait que **le modèle était capable de généraliser la définition d'un plan à l'aide de ces outils**. **Aalors qu'avec l'appel de fonctions, l'agent est finetunét (entraîné) pour utiliser les outils**. ## Comment le modèle apprend-il à prendre une action ? Dans l'Unité 1, nous avons exploré le *workflow* général d'un agent. Une fois que l'utilisateur a donné quelques outils à l'agent et l'a sollicité avec une requête, le modèle va effectuer un cycle à travers : 1. *Réflexion* : Quelle(s) action(s) dois-je prendre pour atteindre l'objectif. 2. *Action* : Formater l'action avec le bon paramètre et arrêter la génération. 3. *Observation* : Récupérer le résultat de l'exécution. Dans une conversation « typique » avec un modèle via une API, la conversation alternera entre les messages utilisateur et assistant comme ceci : ```python conversation = [ {"role": "user", "content": "J'ai besoin d'aide avec ma commande"}, {"role": "assistant", "content": "Je serais ravi de vous aider. Pourriez-vous fournir votre numéro de commande ?"}, {"role": "user", "content": "C'est ORDER-123"}, ] ``` L'appel de fonctions apporte **de nouveaux rôles à la conversation** ! 1. Un nouveau rôle pour une **action** 2. Un nouveau rôle pour une **observation** Si nous prenons l'[API Mistral](https://docs.mistral.ai/capabilities/function_calling/) comme exemple, cela ressemble à ceci : ```python conversation = [ { "role": "user", "content": "Quel est le statut de ma transaction T1001 ?" }, { "role": "assistant", "content": "", "function_call": { "name": "retrieve_payment_status", "arguments": "{\"transaction_id\": \"T1001\"}" } }, { "role": "tool", "name": "retrieve_payment_status", "content": "{\"status\": \"Paid\"}" }, { "role": "assistant", "content": "Votre transaction T1001 a été payée avec succès." } ] ``` > ... Mais vous avez dit qu'il y a un nouveau rôle pour les appels de fonctions ? **Oui et non**, dans ce cas et dans beaucoup d'autres API, le modèle formate l'action à prendre "assistant" comme message. Le gabarit de chat représentera ensuite cela comme des ***tokens* spéciaux** pour l'appel de fonctions. - `[AVAILABLE_TOOLS]` – Démarre la liste des outils disponibles - `[/AVAILABLE_TOOLS]` – Termine la liste des outils disponibles - `[TOOL_CALLS]` – Fait un appel à un outil (c'est-à-dire, prend une action) - `[TOOL_RESULTS]` – Observe le résultat de l'action - `[/TOOL_RESULTS]` – Fin de l'observation (c'est-à-dire, le modèle peut décoder à nouveau) Nous reparlerons de l'appel de fonctions dans ce cours, mais si vous voulez approfondir, vous pouvez consulter [cette excellente section de la documentation de Mistral](https://docs.mistral.ai/capabilities/function_calling/). --- Maintenant que nous avons vu ce qu'est l'appel de fonctions et comment cela fonctionne, **ajoutons cette capacité à un modèle qui n'en dispose pas nativement** : le [google/gemma-2-2b-it](https://huggingface.co/google/gemma-2-2b-it). Pour cela nous allons ajouter de nouveaux *tokens* spéciaux au modèle. Pour être capable de faire ceci, **nous devons d'abord comprendre comment marche le finetuning et la méthode LoRA**. ================================================ FILE: units/fr/bonus-unit2/introduction.mdx ================================================ # Introduction ![Bonus Unit 2 Thumbnail](https://langfuse.com/images/cookbook/huggingface-agent-course/agent-observability-and-evaluation.png) Bienvenue dans l'**Unité Bonus 2** ! Dans ce chapitre, vous explorerez des stratégies avancées pour observer, évaluer et finalement améliorer les performances de vos agents. --- ## 📚 Quand dois-je faire cette Unité Bonus ? Cette unité bonus est parfaite si vous : - **Développez et déployez des agents :** Vous voulez vous assurer que vos agents performent de manière fiable en production. - **Avez besoin d'informations détaillées :** Vous cherchez à diagnostiquer des problèmes, optimiser les performances, ou comprendre le fonctionnement interne de votre agent. - **Visez à réduire les coûts opérationnels :** En surveillant les coûts des agents, la latence et les détails d'exécution, vous pouvez gérer efficacement les ressources. - **Recherchez une amélioration continue :** Vous êtes intéressé par l'intégration de retour utilisateur en temps réel et d'évaluation automatisée dans vos applications. En résumé, pour tous ceux qui veulent mettre leurs agents face à des utilisateurs ! --- ## 🤓 Ce que vous allez apprendre Dans cette unité, vous verrez comment : - **Instrumenter votre agent :** Apprenez comment intégrer des outils d'observabilité via *OpenTelemetry* avec le *framework* smolagents. - **Surveiller les métriques :** Suivez les indicateurs de performance tels que l'utilisation du nombre de *tokens* (coûts), la latence et les traces d'erreur. - **Évaluer en temps réel :** Comprenez les techniques pour l'évaluation en direct, y compris la collecte de retour utilisateur et l'utilisation d'un *LLM-as-a-judge*. - **Analyse hors ligne :** Utilisez des jeux de données de référence (par exemple, GSM8K) pour tester et comparer les performances des agents. --- ## 🚀 Prêt à commencer ? Dans la prochaine section, vous allez voir les bases de l'observabilité et de l'évaluation des agents. Après cela, il sera temps de les voir en action ! ================================================ FILE: units/fr/bonus-unit2/monitoring-and-evaluating-agents-notebook.mdx ================================================ # Observer et évaluer des agents > [!TIP] > Vous pouvez suivre le code dans ce notebook que vous pouvez exécuter avec Google Colab. Dans ce *notebook*, nous apprendrons comment **surveiller les étapes internes (traces) de notre agent** et **évaluer ses performances** en utilisant des outils d'observabilité *open source*. La capacité d'observer et d'évaluer le comportement d'un agent est essentielle pour : - Déboguer les problèmes lorsque les tâches échouent ou produisent des résultats sous-optimaux - Contrôler les coûts et les performances en temps réel - Améliorer la fiabilité et la sécurité grâce à un retour d'information continu ## Prérequis de l'exercice 🏗️ Avant d'exécuter ce *notebook*, assurez-vous d'avoir : 🔲 📚 **Etudier la section [Introduction aux agents](https://huggingface.co/learn/agents-course/fr/unit1/introduction)** 🔲 📚 **Etudier la section [le *framework* smolagents](https://huggingface.co/learn/agents-course/fr/unit2/smolagents/introduction)** ## Étape 0 : Installer les bibliothèques nécessaires Nous aurons besoin de quelques bibliothèques qui nous permettront d'exécuter, de contrôler et d'évaluer nos agents : ```python %pip install langfuse 'smolagents[telemetry]' openinference-instrumentation-smolagents datasets 'smolagents[gradio]' gradio --upgrade ``` ## Étape 1 : Instrumenter votre agent Dans ce *notebook*, nous utiliserons [Langfuse](https://langfuse.com/) comme outil d'observabilité, mais vous pouvez utiliser **n'importe quel autre service compatible avec OpenTelemetry**. Le code ci-dessous montre comment définir les variables d'environnement pour Langfuse (ou n'importe quel *endpoint OTel*) et comment instrumenter votre smolagent. **Note :** Si vous utilisez LlamaIndex ou LangGraph, vous pouvez trouver de la documentation sur leur instrumentation [ici](https://langfuse.com/docs/integrations/llama-index/workflows) et [ici](https://langfuse.com/docs/integrations/langchain/example-python-langgraph). D'abord, configurons les credentials *Langfuse* comme variables d'environnement. Obtenez vos clés API *Langfuse* en vous inscrivant sur [Langfuse Cloud](https://cloud.langfuse.com) ou en [auto-hébergeant Langfuse](https://langfuse.com/self-hosting). ```python import os # Obtenez les clés pour votre projet depuis la page des paramètres du projet : https://cloud.langfuse.com os.environ["LANGFUSE_PUBLIC_KEY"] = "pk-lf-..." os.environ["LANGFUSE_SECRET_KEY"] = "sk-lf-..." os.environ["LANGFUSE_HOST"] = "https://cloud.langfuse.com" # 🇪🇺 région EU # os.environ["LANGFUSE_HOST"] = "https://us.cloud.langfuse.com" # 🇺🇸 région US ``` Nous devons aussi configurer notre token *Hugging Face* pour les appels d'inférence. ```python # Définissez vos tokens/secrets Hugging Face comme variable d'environnement os.environ["HF_TOKEN"] = "hf_..." ``` Avec les variables d'environnement définies, nous pouvons maintenant initialiser le client *Langfuse*. `get_client()` initialise le client *Langfuse* en utilisant les credentials fournis dans les variables d'environnement. ```python from langfuse import get_client langfuse = get_client() # Vérifier la connexion if langfuse.auth_check(): print("Le client Langfuse est authentifié et prêt !") else: print("L'authentification a échoué. Veuillez vérifier vos credentials et hôte.") ``` Ensuite, nous pouvons configurer le `SmolagentsInstrumentor()` pour instrumenter notre *smolagent* et envoyer des traces à *Langfuse*. ```python from openinference.instrumentation.smolagents import SmolagentsInstrumentor SmolagentsInstrumentor().instrument() ``` ## Étape 2 : Testez votre instrumentation Voici un simple *CodeAgent* de smolagents qui calcule `1+1`. Nous l'exécutons pour confirmer que l'instrumentation fonctionne correctement. Si tout est configuré correctement, vous verrez des logs/spans dans votre tableau de bord d'observabilité. ```python from smolagents import InferenceClientModel, CodeAgent # Créer un agent basique pour tester l'instrumentation agent = CodeAgent( tools=[], model=InferenceClientModel() ) agent.run("1+1=") ``` Consultez votre [Langfuse Traces Dashboard](https://cloud.langfuse.com/traces) (ou l'outil d'observabilité de votre choix) pour confirmer que les portées et les logs ont été enregistrés. Exemple de capture d'écran de Langfuse : ![Example trace in Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/first-example-trace.png) _[Lien vers la trace](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/1b94d6888258e0998329cdb72a371155?timestamp=2025-03-10T11%3A59%3A41.743Z)_ ## Étape 3 : Observer et évaluer un agent plus complexe Maintenant que vous avez confirmé que votre instrumentation fonctionne, essayons une requête plus complexe afin de voir comment les mesures avancées (utilisation des *tokens*, latence, coûts, etc.) sont suivies. ```python from smolagents import (CodeAgent, DuckDuckGoSearchTool, InferenceClientModel) search_tool = DuckDuckGoSearchTool() agent = CodeAgent(tools=[search_tool], model=InferenceClientModel()) agent.run("Combien de Rubik's Cubes pourrait-on faire tenir dans la Cathédrale Notre-Dame ?") ``` ### Structure de la trace La plupart des outils d'observabilité enregistrent une **trace** qui contient des **spans**, qui représentent chaque étape de la logique de votre agent. Ici, la trace contient l'exécution globale de l'agent et les sous-périodes pour : - les appels à l'outil (DuckDuckGoSearchTool) - Les appels LLM (InferenceClientModel) Vous pouvez les inspecter pour voir précisément où le temps est passé, combien de *tokens* sont utilisés, etc. : ![Trace tree in Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/trace-tree.png) _[Lien vers la trace](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/1ac33b89ffd5e75d4265b62900c348ed?timestamp=2025-03-07T13%3A45%3A09.149Z&display=preview)_ ## Évaluation en ligne Dans la section précédente, nous avons appris la différence entre l'évaluation en ligne et hors ligne. Nous allons maintenant voir comment surveiller votre agent en production et l'évaluer en direct. ### Métriques courantes à suivre en production 1. **Coûts** - L'instrumentation smolagents capture l'utilisation des *tokens*, que vous pouvez transformer en coûts approximatifs en assignant un prix par *token*. 2. **Latence** - Observez le temps nécessaire à la réalisation de chaque étape ou de l'ensemble de l'exécution. 3. **Retour utilisateur** - Les utilisateurs peuvent fournir un retour direct (pouce vers le haut/vers le bas) pour aider à affiner ou à corriger l'agent. 4. ***LLM-as-a-Judge*** - Utilisez un autre LLM pour évaluer les résultats de votre agent en quasi temps réel (par exemple, vérification de la toxicité ou de l'exactitude des résultats). Ci-dessous, nous montrons des exemples de ces métriques. #### 1. Coûts Vous trouverez ci-dessous une capture d'écran montrant l'utilisation des appels `Qwen2.5-Coder-32B-Instruct`. Ceci est utile pour voir les étapes coûteuses et optimiser votre agent. ![Costs](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/smolagents-costs.png) _[Lien vers la trace](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/1ac33b89ffd5e75d4265b62900c348ed?timestamp=2025-03-07T13%3A45%3A09.149Z&display=preview)_ #### 2. Temps de latence Nous pouvons également voir combien de temps a duré chaque étape. Dans l'exemple ci-dessous, l'ensemble de la conversation a duré 32 secondes, que vous pouvez répartir par étape. Cela vous permet d'identifier les goulets d'étranglement et d'optimiser votre agent. ![Latency](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/smolagents-latency.png) _[Lien vers la trace](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/1ac33b89ffd5e75d4265b62900c348ed?timestamp=2025-03-07T13%3A45%3A09.149Z&display=preview)_blank #### 3. Attributs supplémentaires Vous pouvez également passer des attributs supplémentaires à vos spans. Ceux-ci peuvent inclure `user_id`, `tags`, `session_id`, et des métadonnées personnalisées. Enrichir les traces avec ces détails est important pour l'analyse, le débogage et la surveillance du comportement de votre application à travers différents utilisateurs ou sessions. ```python from smolagents import (CodeAgent, DuckDuckGoSearchTool, InferenceClientModel) search_tool = DuckDuckGoSearchTool() agent = CodeAgent( tools=[search_tool], model=InferenceClientModel() ) with langfuse.start_as_current_span( name="Smolagent-Trace", ) as span: # Exécutez votre application ici response = agent.run("Quelle est la capitale de l'Allemagne ?") # Passez des attributs supplémentaires au span span.update_trace( input="Quelle est la capitale de l'Allemagne ?", output=response, user_id="smolagent-user-123", session_id="smolagent-session-123456789", tags=["question-ville", "test-agents"], metadata={"email": "user@langfuse.com"}, ) # Flusher les événements dans les applications de courte durée langfuse.flush() ``` ![Enhancing agent runs with additional metrics](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/smolagents-attributes.png) #### 4. #### 4. Retour utilisateur Si votre agent est intégré dans une interface utilisateur, vous pouvez enregistrer les réactions directes de l'utilisateur (comme un pouce levé ou baissé dans une interface de discussion). Vous trouverez ci-dessous un exemple utilisant [Gradio](https://gradio.app/) pour intégrer un chat avec un mécanisme de retour d'information simple. Dans l'extrait de code ci-dessous, lorsqu'un utilisateur envoie un message de chat, nous capturons la trace dans Langfuse. Si l'utilisateur aime ou n'aime pas la dernière réponse, nous attribuons un score à la trace. ```python import gradio as gr from smolagents import (CodeAgent, InferenceClientModel) from langfuse import get_client langfuse = get_client() model = InferenceClientModel() agent = CodeAgent(tools=[], model=model, add_base_tools=True) trace_id = None def respond(prompt, history): with langfuse.start_as_current_span( name="Smolagent-Trace"): # Exécutez votre application ici output = agent.run(prompt) global trace_id trace_id = langfuse.get_current_trace_id() history.append({"role": "assistant", "content": str(output)}) return history def handle_like(data: gr.LikeData): # Pour la démonstration, nous mappons les retours utilisateur à 1 (j'aime) ou 0 (je n'aime pas) if data.liked: langfuse.create_score( value=1, name="user-feedback", trace_id=trace_id ) else: langfuse.create_score( value=0, name="user-feedback", trace_id=trace_id ) with gr.Blocks() as demo: chatbot = gr.Chatbot(label="Chat", type="messages") prompt_box = gr.Textbox(placeholder="Tapez votre message...", label="Votre message") # Lorsque l'utilisateur appuie sur "Enter", nous exécutons 'respond' prompt_box.submit( fn=respond, inputs=[prompt_box, chatbot], outputs=chatbot ) # Lorsque l'utilisateur clique sur le bouton "J'aime" d'un message, nous exécutons 'handle_like' chatbot.like(handle_like, None, None) demo.launch() ``` Les retours des utilisateurs sont ensuite saisis dans votre outil d'observabilité : ![User feedback is being captured in Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/user-feedback-gradio.png) #### 5. LLM-as-a-Judge *LLM-as-a-Judge* est une autre façon d'évaluer automatiquement les résultats de votre agent. Vous pouvez configurer l'appel d'un autre LLM pour évaluer l'exactitude, la toxicité, le style ou tout autre critère qui vous intéresse. **Fonctionnement** : 1. Vous définissez un **Modèle d'évaluation**, par exemple, « Vérifier si le texte est toxique ». 2. Chaque fois que votre agent génère un résultat, vous transmettez ce résultat à votre LLM juge avec le gabarit. 3. Le LLM juge répond avec un score ou une étiquette que vous enregistrez dans votre outil d'observabilité. Exemple de Langfuse : ![LLM-as-a-Judge Evaluation Template](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/evaluator-template.png) ![LLM-as-a-Judge Evaluator](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/evaluator.png) ```python # Exemple : Vérifier si la sortie de l'agent est toxique ou non from smolagents import (CodeAgent, DuckDuckGoSearchTool, InferenceClientModel) search_tool = DuckDuckGoSearchTool() agent = CodeAgent(tools=[search_tool], model=InferenceClientModel()) agent.run("Manger des carottes peut-il améliorer votre vision ?") ``` Vous pouvez voir que la réponse de cet exemple est jugée « non toxique ». ![LLM-as-a-Judge Evaluation Score](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/llm-as-a-judge-score.png) #### 6. Aperçu des métriques d'observabilité Toutes ces métriques peuvent être visualisées ensemble dans des tableaux de bord. Cela vous permet de voir rapidement les performances de votre agent sur plusieurs sessions et vous aide à suivre les mesures de qualité au fil du temps. ![Observability metrics overview](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/langfuse-dashboard.png) ## Évaluation hors ligne L'évaluation en ligne est essentielle pour obtenir un retour d'information en temps réel, mais vous avez également besoin d'une **évaluation hors ligne**, c'est-à-dire de vérifications systématiques avant ou pendant le développement. Cela permet de maintenir la qualité et la fiabilité avant de mettre les changements en production. ### Évaluation d'un jeu de données Lors d'une évaluation hors ligne, vous devez généralement 1. Disposer d'un jeu de données de référence (avec des paires de *prompts* et de résultats attendus) 2. Exécuter votre agent sur ce jeu de données 3. Comparer les résultats aux résultats attendus ou utiliser un mécanisme de notation supplémentaire. Ci-dessous, nous démontrons cette approche avec le jeu de données [GSM8K](https://huggingface.co/datasets/gsm8k), qui contient des questions et des solutions mathématiques. ```python import pandas as pd from datasets import load_dataset # Récupérer GSM8K sur Hugging Face dataset = load_dataset("openai/gsm8k", 'main', split='train') df = pd.DataFrame(dataset) print("Premières lignes du jeu de données GSM8K :") print(df.head()) ``` Ensuite, nous créons un jeu de données dans Langfuse pour suivre les exécutions. Nous ajoutons ensuite chaque élément du jeu de données au système. (Si vous n'utilisez pas Langfuse, vous pouvez simplement les stocker dans votre propre base de données ou dans un fichier local à des fins d'analyse). ```python from langfuse import get_client langfuse = get_client() langfuse_dataset_name = "gsm8k_dataset_huggingface" # Créer un jeu de données dans Langfuse langfuse.create_dataset( name=langfuse_dataset_name, description="Jeu de données de référence GSM8K téléchargé depuis Huggingface", metadata={ "date": "2025-03-10", "type": "benchmark" } ) ``` ```python for idx, row in df.iterrows(): langfuse.create_dataset_item( dataset_name=langfuse_dataset_name, input={"text": row["question"]}, expected_output={"text": row["answer"]}, metadata={"source_index": idx} ) if idx >= 9: # Télécharger seulement les 10 premiers éléments pour la démonstration break ``` ![Dataset items in Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/example-dataset.png) #### Exécution de l'agent sur le jeu de données Nous définissons une fonction d'aide `run_smolagent()` qui : 1. Démarre un span Langfuse 2. Exécute notre agent sur le *prompt* 3. Enregistre l'ID de la trace dans Langfuse Ensuite, nous parcourons en boucle chaque élément de l'ensemble de données, nous exécutons l'agent et nous lions la trace à l'élément de l'ensemble de données. Nous pouvons également joindre une note d'évaluation rapide si vous le souhaitez. ```python from opentelemetry.trace import format_trace_id from smolagents import (CodeAgent, InferenceClientModel, LiteLLMModel) from langfuse import get_client langfuse = get_client() # Exemple : utiliser InferenceClientModel ou LiteLLMModel pour accéder aux modèles openai, anthropic, gemini, etc. : model = InferenceClientModel() agent = CodeAgent( tools=[], model=model, add_base_tools=True ) dataset_name = "gsm8k_dataset_huggingface" current_run_name = "smolagent-notebook-run-01" # Identifie cette exécution d'évaluation spécifique # Supposons que 'run_smolagent' est votre fonction d'application instrumentée def run_smolagent(question): with langfuse.start_as_current_generation(name="qna-llm-call") as generation: # Simuler un appel LLM result = agent.run(question) # Mettre à jour la trace avec l'entrée et la sortie generation.update_trace( input= question, output=result, ) return result dataset = langfuse.get_dataset(name=dataset_name) # Récupérer votre jeu de données pré-peuplé for item in dataset.items: # Utiliser le gestionnaire de contexte item.run() with item.run( run_name=current_run_name, run_metadata={"model_provider": "Hugging Face", "temperature_setting": 0.7}, run_description="Exécution d'évaluation pour le jeu de données GSM8K" ) as root_span: # root_span est le span racine de la nouvelle trace pour cet élément et exécution. # Toutes les opérations langfuse suivantes dans ce bloc font partie de cette trace. # Appelez votre logique d'application generated_answer = run_smolagent(question=item.input["text"]) print(item.input) ``` Vous pouvez répéter ce processus avec différents : - Modèles (OpenAI GPT, LLM local, etc.) - Outils (recherche ou pas recherche) - Prompts (différents messages du système) Ensuite, comparez-les côte à côte dans votre outil d'observabilité : ![Dataset run overview](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/dataset_runs.png) ![Dataset run comparison](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/dataset-run-comparison.png) ## Réflexions finales Dans ce *notebook*, nous avons vu comment : 1. **Mettre en place l'observabilité** en utilisant les exportateurs smolagents + OpenTelemetry 2. **Vérifier l'instrumentation** en lançant un agent simple 3. **Capturez des métriques détaillées** (coût, latence, etc.) à l'aide d'outils d'observabilité 4. **Recueillir les commentaires des utilisateurs** via une interface Gradio 5. **Utiliser un LLM-as-a-Judge** pour évaluer automatiquement les résultats 6. **Effectuer une évaluation hors ligne** avec un jeu de données de référence 🤗 Bon codage ! ================================================ FILE: units/fr/bonus-unit2/quiz.mdx ================================================ # Quiz : évaluation des agents Évaluons votre compréhension des concepts de traçage et d'évaluation des agents abordés dans cette unité bonus. Ce quiz est optionnel et non noté. ### Q1 : À quoi l'observabilité dans les agents fait-elle principalement référence ? Quelle déclaration décrit avec précision le but de l'observabilité pour les agents ? spans pour comprendre le comportement de l'agent.", explain: "Correct ! L'observabilité signifie utiliser des logs, métriques et spans pour éclairer le fonctionnement interne de l'agent.", correct: true }, { text: "Elle se concentre sur la réduction du coût financier d'exécution de l'agent.", explain: "L'observabilité couvre les coûts mais ne s'y limite pas." }, { text: "Elle se réfère à l'apparence externe et l'interface utilisateur de l'agent.", explain: "L'observabilité concerne les processus internes, pas l'interface utilisateur." }, { text: "Elle ne concerne que le style de code et l'esthétique du code.", explain: "Le style de code n'est pas lié à l'observabilité dans ce contexte." } ]} /> ### Q2 : Laquelle des suivantes N'EST PAS une métrique commune surveillée dans l'observabilité des agents ? Sélectionnez la métrique qui ne tombe pas typiquement sous le parapluie de l'observabilité. ### Q3 : Qu'est-ce qui décrit le mieux l'évaluation hors ligne d'un agent ? Déterminez la déclaration qui capture correctement l'essence de l'évaluation hors ligne. ### Q4 : Quel avantage l'évaluation en ligne des agents offre-t-elle ? Choisissez la déclaration qui reflète le mieux l'avantage de l'évaluation en ligne. benchmarks.", explain: "Les évaluations hors ligne et en ligne sont importantes et complémentaires." }, { text: "Elle se concentre uniquement sur la réduction du coût computationnel de l'agent.", explain: "Le suivi des coûts fait partie de l'observabilité, pas l'avantage principal de l'évaluation en ligne." } ]} /> ### Q5 : Quel rôle OpenTelemetry joue-t-il dans l'observabilité et l'évaluation des agents ? Quelle déclaration décrit le mieux le rôle d'OpenTelemetry dans la surveillance des agents ? framework standardisé pour instrumenter le code, permettant la collecte de traces, métriques et logs pour l'observabilité.", explain: "Correct ! OpenTelemetry standardise l'instrumentation pour les données de télémétrie, ce qui est crucial pour surveiller et diagnostiquer le comportement des agents.", correct: true }, { text: "Il agit comme un remplacement pour le débogage manuel en corrigeant automatiquement les problèmes de code.", explain: "Incorrect. OpenTelemetry est utilisé pour rassembler des données de télémétrie, pas pour déboguer les problèmes de code." }, { text: "Il sert principalement comme une base de données pour stocker les logs historiques sans capacités temps réel.", explain: "Incorrect. OpenTelemetry se concentre sur la collecte de données de télémétrie en temps réel et l'export de données vers des outils d'analyse." }, { text: "Il est utilisé pour optimiser les performances computationnelles de l'agent en ajustant automatiquement les paramètres du modèle.", explain: "Incorrect. OpenTelemetry est centré sur l'observabilité plutôt que sur l'ajustement des performances." } ]} /> Félicitations pour avoir terminé ce quiz ! 🎉 Si vous avez manqué des questions, revoyez le contenu de cette unité bonus pour une compréhension plus approfondie. Si vous avez bien réussi, vous êtes prêt à explorer des sujets plus avancés en observabilité et évaluation des agents ! ================================================ FILE: units/fr/bonus-unit2/what-is-agent-observability-and-evaluation.mdx ================================================ # Qu'est-ce que l'observabilité et l'évaluation des agents ? ## 🔎 Qu'est-ce que l'Observabilité ? L'observabilité consiste à comprendre ce qui se passe à l'intérieur de votre agent en regardant des signaux externes comme les logs, les métriques et les traces. Pour les agents, cela signifie suivre les actions, l'utilisation des outils, les appels de modèles et les réponses pour déboguer et améliorer les performances de l'agent. ![Observability dashboard](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/langfuse-dashboard.png) ## 🔭 Pourquoi l'observabilité des agents est importante Sans observabilité, les agents sont des « boîtes noires ». Les outils d'observabilité rendent les agents transparents, vous permettant de : - Comprendre les compromis entre coûts et précision - Mesurer la latence - Détecter le langage nuisible et l'injection de *prompts* - Surveiller les retours utilisateur En d'autres termes, cela permet de passer votre agent de démonstration à de la production ! ## 🔨 Outils d'observabilité Les outils d'observabilité courants pour les agents incluent des plateformes comme [Langfuse](https://langfuse.com) et [Arize](https://www.arize.com). Ces outils aident à collecter des traces détaillées et offrent des tableaux de bord pour surveiller les métriques en temps réel, facilitant la détection de problèmes et l'optimisation des performances. Les outils d'observabilité varient largement dans leurs fonctionnalités et capacités. Certains outils sont *open source*, bénéficiant de grandes communautés qui façonnent leurs feuilles de route et de nombreuses intégrations. De plus, certains outils se spécialisent dans des aspects spécifiques des LLMOps (comme l'observabilité, les évaluations ou la gestion des prompts) tandis que d'autres sont conçus pour couvrir l'ensemble du *workflow* LLMOps. Nous vous encourageons à explorer la documentation de différentes options pour choisir la solution qui fonctionne bien pour vous. De nombreux *frameworks* d'agents tels que [smolagents](https://huggingface.co/docs/smolagents/v1.12.0/en/index) utilisent le standard [OpenTelemetry](https://opentelemetry.io/docs/) pour exposer les métadonnées aux outils d'observabilité. En plus de cela, les outils d'observabilité construisent des instrumentations personnalisées pour permettre plus de flexibilité dans le monde en mouvement rapide des LLM. Vous devriez consulter la documentation de l'outil que vous utilisez pour voir ce qui est pris en charge. ## 🔬Traces et *Spans* Les outils d'observabilité représentent généralement les exécutions d'agents comme des traces et des *spans*. - **Les traces** représentent une tâche d'agent complète du début à la fin (comme traiter une requête utilisateur). - **Les spans** sont des étapes individuelles dans la trace (comme appeler un modèle de langage ou récupérer des données). ![Example of a smolagent trace in Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/trace-tree.png) ## 📊 Métriques clés à surveiller Voici quelques-unes des métriques les plus courantes que les outils d'observabilité surveillent : **Latence :** À quelle vitesse l'agent répond-il ? Les longs temps d'attente impactent négativement l'expérience utilisateur. Vous devriez mesurer la latence pour les tâches et les étapes individuelles en traçant les exécutions d'agent. Par exemple, un agent qui prend 20 secondes pour tous les appels de modèle pourrait être accéléré en utilisant un modèle plus rapide ou en exécutant les appels de modèle en parallèle. **Coûts :** Quelle est la dépense par exécution d'agent ? Les agents IA s'appuient sur des LLM facturés par *token* ou des API externes. L'utilisation fréquente d'outils ou de beaucoup de *prompts* peut rapidement augmenter les coûts. Par exemple, si un agent appelle un *LLM* cinq fois pour une amélioration de qualité marginale, vous devez évaluer si le coût est justifié ou si vous pourriez réduire le nombre d'appels ou utiliser un modèle moins cher. La surveillance en temps réel peut aussi aider à identifier des pics inattendus (par exemple, des bugs causant des boucles d'API excessives). **Erreurs de requête :** Combien de requêtes l'agent a-t-il échouées ? Cela peut inclure des erreurs d'API ou des appels d'outils échoués. Pour rendre votre agent plus robuste contre ceux-ci en production, vous pouvez ensuite mettre en place des solutions de secours ou des tentatives. Par exemple, si le fournisseur de LLM A est en panne, vous basculez vers le fournisseur de LLM B comme *backup*. **Retours utilisateur :** Implémenter des évaluations utilisateur directes fournit des informations précieuses. Cela peut inclure des évaluations explicites (pouces levés 👍/baissés 👎, ⭐1-5 étoiles) ou des commentaires textuels. Des commentaires négatifs devraient vous alerter car c'est un signe que l'agent ne fonctionne pas comme prévu. **Retours utilisateur implicites :** Les comportements utilisateur fournissent des commentaires indirects même sans évaluations explicites. Cela peut inclure la reformulation immédiate de questions, des requêtes répétées ou cliquer sur un bouton de réessai. Par exemple, si vous voyez que les utilisateurs posent répétitivement la même question, c'est un signe que l'agent ne fonctionne pas comme prévu. **Précision :** À quelle fréquence l'agent produit-il des sorties correctes ou souhaitables ? Les définitions de précision varient (par exemple, exactitude de résolution de problèmes, précision de récupération d'informations, satisfaction utilisateur). La première étape est de définir à quoi ressemble le succès pour votre agent. Vous pouvez suivre la précision via des vérifications automatisées, des scores d'évaluation ou des labels de réussite de tâches. Par exemple, marquer les traces comme « réussies » ou « échouées ». **Métriques d'évaluation automatisée :** Vous pouvez aussi mettre en place des évaluations automatisées. Par exemple, vous pouvez utiliser un LLM pour noter la sortie de l'agent, par exemple si elle est utile, précise ou non. Il existe aussi plusieurs bibliothèques *open source* qui vous aident à noter différents aspects de l'agent. Par exemple [RAGAS](https://docs.ragas.io/) pour les agents RAG ou [LLM Guard](https://llm-guard.com/) pour détecter le langage nuisible ou l'injection de *prompts*. En pratique, une combinaison de ces métriques donne la meilleure couverture de la santé d'un agent IA. Dans le [*notebook* d'exemple](https://colab.research.google.com/#fileId=https://huggingface.co/agents-course/notebooks/blob/main/fr/bonus-unit2/monitoring-and-evaluating-agents.ipynb) de ce chapitre, nous vous montrerons à quoi ressemblent ces métriques dans des exemples réels mais d'abord, nous apprendrons à quoi ressemble un *workflow* d'évaluation typique. ## 👍 Évaluation des agents L'observabilité nous donne des métriques, mais l'évaluation est le processus d'analyser ces données (et d'effectuer des tests) pour déterminer à quel point un agent performe et comment il peut être amélioré. En d'autres termes, une fois que vous avez ces traces et métriques, comment les utilisez-vous pour juger l'agent et prendre des décisions ? L'évaluation standard est importante car les agents sont souvent non-déterministes et peuvent évoluer (par des mises à jour ou un comportement de modèle dérivant) – sans évaluation, vous ne sauriez pas si votre agent fait réellement bien son travail ou s'il a régressé. Il y a deux catégories d'évaluations pour les agents : **l'évaluation en ligne** et **l'évaluation hors ligne**. Les deux sont précieuses, et elles se complètent. Nous commençons généralement par l'évaluation hors ligne, car c'est l'étape minimum nécessaire avant de déployer tout agent. ### 🥷 Évaluation hors ligne ![Dataset items in Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/example-dataset.png) Cela implique d'évaluer l'agent dans un environnement contrôlé, typiquement en utilisant des jeux de données de test, pas des requêtes utilisateur en direct. Vous utilisez des jeux de données organisés où vous savez quelle est la sortie attendue ou le comportement correct, puis vous exécutez votre agent sur ceux-ci. Par exemple, si vous avez construit un agent résolvant des problèmes mathématiques, vous pourriez avoir un [jeu de données de test](https://huggingface.co/datasets/gsm8k) de 100 problèmes avec des réponses connues. L'évaluation hors ligne est souvent effectuée pendant le développement (et peut faire partie des pipelines CI/CD) pour vérifier les améliorations ou se protéger contre les régressions. L'avantage est que c'est **répétable et vous pouvez obtenir des métriques de précision claires puisque vous avez la vérité terrain**. Vous pourriez aussi simuler des requêtes utilisateur et mesurer les réponses de l'agent contre des réponses idéales ou utiliser des métriques automatisées comme décrit ci-dessus. Le défi clé avec l'évaluation hors ligne est d'assurer que votre jeu de données de test est complet et reste pertinent : l'agent pourrait bien performer sur un jeu de test fixe mais rencontrer des requêtes très différentes en production. Par conséquent, vous devriez garder les jeux de test mis à jour avec de nouveaux cas limites et des exemples qui reflètent des scénarios du monde réel. Un mélange de petits cas de *smoke test* et de plus grands jeux d'évaluation est utile : les petits jeux pour des vérifications rapides et les plus grands pour des métriques de performance plus larges. ### 🔄 Évaluation en ligne Cela se réfère à l'évaluation de l'agent dans un environnement en direct, du monde réel, c'est-à-dire pendant l'utilisation réelle en production. L'évaluation en ligne implique de surveiller les performances de l'agent sur de vraies interactions utilisateur et d'analyser les résultats en continu. Par exemple, vous pourriez suivre les taux de succès, les scores de satisfaction utilisateur, ou d'autres métriques sur le trafic en direct. L'avantage de l'évaluation en ligne est qu'elle **capture des choses que vous pourriez ne pas anticiper dans un environnement de laboratoire**. Vous pouvez observer la dérive du modèle au fil du temps (si l'efficacité de l'agent se dégrade quand les entrées changent) et attraper des requêtes ou situations inattendues qui n'étaient pas dans vos données de test. Elle fournit une vraie image de comment l'agent se comporte dans la nature. L'évaluation en ligne implique souvent de collecter des retours utilisateur implicites et explicites, comme discuté, et possiblement d'exécuter des *shadow tests* ou des tests A/B (où une nouvelle version de l'agent fonctionne en parallèle pour comparer à l'ancienne). Le défi est qu'il peut être délicat d'obtenir des labels ou scores fiables pour les interactions en direct. Vous pourriez vous appuyer sur les retours utilisateur ou des métriques en aval (comme est-ce que l'utilisateur a cliqué sur le résultat). ### 🤝 Combiner les deux En pratique, l'évaluation réussie d'agent mélange les méthodes **en ligne** et **hors ligne**. Vous pourriez exécuter des *benchmarks* hors ligne standards pour noter quantitativement votre agent sur des tâches définies et surveiller continuellement l'utilisation en direct pour attraper des choses que les *benchmarks* ratent. Par exemple, les tests hors ligne peuvent attraper si le taux de succès d'un agent de génération de code sur un jeu connu de problèmes s'améliore, tandis que la surveillance en ligne pourrait vous alerter que les utilisateurs ont commencé à poser une nouvelle catégorie de question avec laquelle l'agent lutte. Combiner les deux donne une image plus robuste. En fait, de nombreuses équipes adoptent une boucle : _évaluation hors ligne → déployer une nouvelle version d'agent → surveiller les métriques en ligne et collecter de nouveaux exemples d'échec → ajouter ces exemples au jeu de test hors ligne → itérer_. De cette façon, l'évaluation est continue et s'améliore constamment. ## 🧑‍💻 Voyons comment cela fonctionne en pratique Dans la prochaine section, nous verrons des exemples de comment nous pouvons utiliser des outils d'observabilité pour surveiller et évaluer notre agent. ================================================ FILE: units/fr/bonus-unit3/building_your_pokemon_agent.mdx ================================================ # Construire un agent de combat Pokémon Maintenant que vous avez exploré le potentiel et les limitations de l'IA agentique dans les jeux vidéos, il est temps de passer à la pratique. Dans cette section, vous allez **construire votre propre agent pour combattre dans un combat au tour par tour dans le style de Pokémon**, en utilisant tout ce que vous avez appris à travers le cours. Nous décomposerons le système en quatre blocs de construction clés : - **Poke-env :** Une bibliothèque Python conçue pour entraîner des bots Pokémon basés sur des règles ou par apprentissage par renforcement. - **Pokémon Showdown :** Un simulateur de combat en ligne où votre agent combattra. - **LLMAgentBase :** Une classe Python personnalisée que nous avons construite pour connecter votre LLM avec l'environnement de combat *Poke-env*. - **TemplateAgent :** Un *template* de démarrage que vous compléterez pour créer votre propre agent de combat personnalisé. Explorons chacun de ces composants plus en détail. ## 🧠 Poke-env ![Battle gif](https://github.com/hsahovic/poke-env/raw/master/rl-gif.gif) [Poke-env](https://github.com/hsahovic/poke-env) est une interface Python originellement construite pour entraîner des bots d'apprentissage par renforcement par [Haris Sahovic](https://huggingface.co/hsahovic), mais nous l'avons réutilisée pour l'IA agentique. Elle permet à votre agent d'interagir avec *Pokémon Showdown* à travers une API simple. Elle fournit une classe `Player` de laquelle votre agent héritera, couvrant tout ce qui est nécessaire pour communiquer avec l'interface graphique. **Documentation** : [poke-env.readthedocs.io](https://poke-env.readthedocs.io/en/stable/) **Dépôt** : [github.com/hsahovic/poke-env](https://github.com/hsahovic/poke-env) ## ⚔️ Pokémon Showdown [Pokémon Showdown](https://pokemonshowdown.com/) est un simulateur de combat [*open-source*](https://github.com/smogon/Pokemon-Showdown) où votre agent jouera des combats Pokémon en direct. Il fournit une interface complète pour simuler et afficher des combats en temps réel. Dans notre défi, le bot agira exactement comme un joueur humain, choisissant des mouvements tour par tour. Nous avons déployé un serveur que tous les participants utiliseront pour combattre. Voyons qui construit le meilleur agent de combat ! **Dépôt** : [github.com/smogon/Pokemon-Showdown](https://github.com/smogon/Pokemon-Showdown) **Site web** : [pokemonshowdown.com](https://pokemonshowdown.com/) ## 🔌 LLMAgentBase `LLMAgentBase` est une classe Python qui étend la classe `Player` de **Poke-env**. Elle sert de pont entre votre **LLM** et le **simulateur de combat Pokémon**, gérant le formatage d'entrée/sortie et maintenant le contexte de combat. Cet agent de base fournit un ensemble d'outils (définis dans `STANDARD_TOOL_SCHEMA`) pour interagir avec l'environnement, incluant : - `choose_move` : pour sélectionner une attaque pendant le combat - `choose_switch` : pour changer de Pokémon Le LLM devrait utiliser ces outils pour prendre des décisions pendant un match. ### 🧠 Logique centrale - `choose_move(battle: Battle)` : La méthode principale invoquée à chaque tour. Elle prend un objet `Battle` et retourne une chaîne d'action basée sur la sortie du LLM. ### 🔧 Méthodes internes clés - `_format_battle_state(battle)` : Convertit l'état actuel du combat en chaîne, la rendant adaptée pour l'envoi au LLM. - `_find_move_by_name(battle, move_name)` : Trouve un mouvement par nom, utilisé dans les réponses LLM qui appellent `choose_move`. - `_find_pokemon_by_name(battle, pokemon_name)` : Localise un Pokémon spécifique vers lequel changer, basé sur la commande de changement du LLM. - `_get_llm_decision(battle_state)` : Cette méthode est abstraite dans la classe de base. Vous devrez l'implémenter dans votre propre agent (voir prochaine section), où vous définissez comment interroger le LLM et analyser sa réponse. Voici un extrait montrant comment cette prise de décision fonctionne : ```python STANDARD_TOOL_SCHEMA = { "choose_move": { ... }, "choose_switch": { ... }, } class LLMAgentBase(Player): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.standard_tools = STANDARD_TOOL_SCHEMA self.battle_history = [] def _format_battle_state(self, battle: Battle) -> str: active_pkmn = battle.active_pokemon active_pkmn_info = f"Your active Pokemon: {active_pkmn.species} " \ f"(Type: {'/'.join(map(str, active_pkmn.types))}) " \ f"HP: {active_pkmn.current_hp_fraction * 100:.1f}% " \ f"Status: {active_pkmn.status.name if active_pkmn.status else 'None'} " \ f"Boosts: {active_pkmn.boosts}" opponent_pkmn = battle.opponent_active_pokemon opp_info_str = "Unknown" if opponent_pkmn: opp_info_str = f"{opponent_pkmn.species} " \ f"(Type: {'/'.join(map(str, opponent_pkmn.types))}) " \ f"HP: {opponent_pkmn.current_hp_fraction * 100:.1f}% " \ f"Status: {opponent_pkmn.status.name if opponent_pkmn.status else 'None'} " \ f"Boosts: {opponent_pkmn.boosts}" opponent_pkmn_info = f"Opponent's active Pokemon: {opp_info_str}" available_moves_info = "Available moves:\n" if battle.available_moves: available_moves_info += "\n".join( [f"- {move.id} (Type: {move.type}, BP: {move.base_power}, Acc: {move.accuracy}, PP: {move.current_pp}/{move.max_pp}, Cat: {move.category.name})" for move in battle.available_moves] ) else: available_moves_info += "- None (Must switch or Struggle)" available_switches_info = "Available switches:\n" if battle.available_switches: available_switches_info += "\n".join( [f"- {pkmn.species} (HP: {pkmn.current_hp_fraction * 100:.1f}%, Status: {pkmn.status.name if pkmn.status else 'None'})" for pkmn in battle.available_switches] ) else: available_switches_info += "- None" state_str = f"{active_pkmn_info}\n" \ f"{opponent_pkmn_info}\n\n" \ f"{available_moves_info}\n\n" \ f"{available_switches_info}\n\n" \ f"Weather: {battle.weather}\n" \ f"Terrains: {battle.fields}\n" \ f"Your Side Conditions: {battle.side_conditions}\n" \ f"Opponent Side Conditions: {battle.opponent_side_conditions}" return state_str.strip() def _find_move_by_name(self, battle: Battle, move_name: str) -> Optional[Move]: normalized_name = normalize_name(move_name) # Prioriser la correspondance exacte d'ID for move in battle.available_moves: if move.id == normalized_name: return move # Solution de secours : Vérifier le nom d'affichage (moins fiable) for move in battle.available_moves: if move.name.lower() == move_name.lower(): print(f"Warning: Matched move by display name '{move.name}' instead of ID '{move.id}'. Input was '{move_name}'.") return move return None def _find_pokemon_by_name(self, battle: Battle, pokemon_name: str) -> Optional[Pokemon]: normalized_name = normalize_name(pokemon_name) for pkmn in battle.available_switches: # Normaliser le nom d'espèce pour la comparaison if normalize_name(pkmn.species) == normalized_name: return pkmn return None async def choose_move(self, battle: Battle) -> str: battle_state_str = self._format_battle_state(battle) decision_result = await self._get_llm_decision(battle_state_str) print(decision_result) decision = decision_result.get("decision") error_message = decision_result.get("error") action_taken = False fallback_reason = "" if decision: function_name = decision.get("name") args = decision.get("arguments", {}) if function_name == "choose_move": move_name = args.get("move_name") if move_name: chosen_move = self._find_move_by_name(battle, move_name) if chosen_move and chosen_move in battle.available_moves: action_taken = True chat_msg = f"AI Decision: Using move '{chosen_move.id}'." print(chat_msg) return self.create_order(chosen_move) else: fallback_reason = f"LLM chose unavailable/invalid move '{move_name}'." else: fallback_reason = "LLM 'choose_move' called without 'move_name'." elif function_name == "choose_switch": pokemon_name = args.get("pokemon_name") if pokemon_name: chosen_switch = self._find_pokemon_by_name(battle, pokemon_name) if chosen_switch and chosen_switch in battle.available_switches: action_taken = True chat_msg = f"AI Decision: Switching to '{chosen_switch.species}'." print(chat_msg) return self.create_order(chosen_switch) else: fallback_reason = f"LLM chose unavailable/invalid switch '{pokemon_name}'." else: fallback_reason = "LLM 'choose_switch' called without 'pokemon_name'." else: fallback_reason = f"LLM called unknown function '{function_name}'." if not action_taken: if not fallback_reason: if error_message: fallback_reason = f"API Error: {error_message}" elif decision is None: fallback_reason = "LLM did not provide a valid function call." else: fallback_reason = "Unknown error processing LLM decision." print(f"Warning: {fallback_reason} Choosing random action.") if battle.available_moves or battle.available_switches: return self.choose_random_move(battle) else: print("AI Fallback: No moves or switches available. Using Struggle/Default.") return self.choose_default_move(battle) async def _get_llm_decision(self, battle_state: str) -> Dict[str, Any]: raise NotImplementedError("Subclasses must implement _get_llm_decision") ``` **Code source complet** : [agents.py](https://huggingface.co/spaces/Jofthomas/twitch_streaming/blob/main/agents.py) ## 🧪 TemplateAgent Maintenant vient la partie amusante ! Avec `LLMAgentBase` comme fondation, il est temps d'implémenter votre propre agent, avec votre propre stratégie pour grimper dans le classement. Vous commencerez à partir de ce *template* et construirez votre propre logique. Nous avons aussi fourni trois [exemples complets](https://huggingface.co/spaces/Jofthomas/twitch_streaming/blob/main/agents.py) utilisant les modèles **OpenAI**, **Mistral** et **Gemini** pour vous guider. Voici une version simplifiée du *template* : ```python class TemplateAgent(LLMAgentBase): """Utilise l'API Template AI pour prendre des décisions.""" def __init__(self, api_key: str = None, model: str = "model-name", *args, **kwargs): super().__init__(*args, **kwargs) self.model = model self.template_client = TemplateModelProvider(api_key=...) self.template_tools = list(self.standard_tools.values()) async def _get_llm_decision(self, battle_state: str) -> Dict[str, Any]: """Envoie l'état au LLM et reçoit en retour la décision relative à l'appel de fonction.""" system_prompt = ( "You are a ..." ) user_prompt = f"..." try: response = await self.template_client.chat.completions.create( model=self.model, messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt}, ], ) message = response.choices[0].message return {"decision": {"name": function_name, "arguments": arguments}} except Exception as e: print(f"Unexpected error during call: {e}") return {"error": f"Unexpected error: {e}"} ``` Ce code ne fonctionnera pas directement, c'est un plan pour votre cas personnalisé. Avec toutes les pièces prêtes, c'est à votre tour de construire un agent compétitif. Dans la prochaine section, nous montrerons comment déployer votre agent sur notre serveur et combattre d'autres en temps réel. Que le combat commence ! 🔥 ================================================ FILE: units/fr/bonus-unit3/conclusion.mdx ================================================ # Conclusion Si vous êtes arrivé jusqu'ici, félicitations ! 🥳 Vous avez construit avec succès votre propre agent de combat Pokémon ! ⚔️🎮 Vous avez maîtrisé les fondamentaux des **flux de travail agentiques**, connecté un **LLM** à un environnement de jeu, et déployé un Agent intelligent prêt à affronter les défis du combat. Mais le voyage ne s'arrête pas là ! Maintenant que vous avez votre premier Agent en fonctionnement, réfléchissez à comment vous pouvez le faire évoluer davantage : - Pouvez-vous améliorer sa réflexion stratégique ? - Comment un mécanisme de mémoire ou une boucle de *feedback* changerait-il ses performances ? - Quelles expériences pourraient aider à le rendre plus compétitif en combat ? Nous aimerions entendre vos pensées sur le cours et comment nous pouvons le rendre encore meilleur pour les futurs apprenants. Vous avez des commentaires ? 👉 [Remplissez ce formulaire](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog). Merci d'avoir appris avec nous, et souvenez-vous : **Continuez à apprendre, continuez à vous entraîner, continuez à combattre, et restez impressionnants !** 🤗 ================================================ FILE: units/fr/bonus-unit3/from-llm-to-agents.mdx ================================================ # Des LLM aux agents Nous avons appris dans la [première unité](https://huggingface.co/learn/agents-course/unit1/introduction) du cours que les agents sont capables de planifier et prendre des décisions. Et tandis que les LLM ont permis des interactions plus naturelles avec les PNJ, l'IA agentique va plus loin en permettant aux personnages de prendre des décisions, planifier des actions et s'adapter à des environnements changeants. Pour illustrer la différence, pensez à un PNJ de RPG classique : - Avec un LLM : le PNJ pourrait répondre à vos questions de manière plus naturelle et variée. C'est génial pour le dialogue, mais le PNJ reste statique, il n'agira pas à moins que vous fassiez quelque chose en premier. - Avec l'IA Agentique : le PNJ peut décider d'aller chercher de l'aide, tendre un piège, ou vous éviter complètement, même si vous n'interagissez pas directement avec lui. Cette petite modification change tout. Nous passons de répondants scriptés à des acteurs autonomes dans le monde du jeu. Ce changement signifie que les PNJ peuvent maintenant interagir directement avec leur environnement à travers des comportements dirigés par des objectifs, menant finalement à un gameplay plus dynamique et imprévisible. L'IA agentique donne aux PNJ : - **L'autonomie** : Prendre des décisions indépendantes basées sur l'état du jeu. - **L'adaptabilité** : Ajuster les stratégies en réponse aux actions du joueur. - **La persistance** : Se souvenir d'interactions passées pour informer le comportement futur. Cela transforme les PNJ d'entités réactives (réagissant à vos entrées) en participants proactifs dans le monde du jeu, ouvrant la porte à un *gameplay* innovant. ## La grande limitation des agents : **c'est lent** (pour l'instant) Cependant, ne soyons pas trop optimistes pour l'instant. Malgré son potentiel, l'IA agentique fait actuellement face à des défis dans les applications temps réel. Les processus de raisonnement et planification peuvent introduire de la latence, la rendant moins adaptée aux jeux rapides comme *Doom* ou *Super Mario Bros*. Prenez l'exemple de [_Claude Plays Pokémon_](https://www.twitch.tv/claudeplayspokemon). Si vous considérez le nombre de *tokens* nécessaires pour **penser**, plus les *tokens* nécessaires pour **agir**, il devient clair que nous aurons besoin de stratégies de décodage entièrement différentes pour rendre le jeu temps réel faisable. Claude plays Pokémon La plupart des jeux ont besoin de tourner autour de 30 FPS, ce qui signifie qu'un agent en temps réel aura besoin d'agir 30 fois par seconde, ce qui n'est pas actuellement faisable avec les LLM d'aujourd'hui. Cependant, les jeux au tour par tour comme *Pokémon* sont des candidats idéaux, car ils permettent à l'IA suffisamment de temps pour délibérer et prendre des décisions stratégiques. C'est pourquoi dans la prochaine section, vous construirez votre propre agent pour combattre dans un combat au tour par tour dans le style de Pokémon, et même le défier vous-même. C'est parti ! ================================================ FILE: units/fr/bonus-unit3/introduction.mdx ================================================ # Introduction Bonus Unit 3 AI in Games 🎶Je veux être le meilleur... 🎶 Bienvenue dans cette **unité bonus**, où vous explorerez l'intersection passionnante entre **les agents et les jeux vidéos** ! 🎮🤖 Imaginez un jeu où les personnages non-joueurs (PNJ) ne suivent pas simplement des lignes scriptées, mais tiennent plutôt des conversations dynamiques, s'adaptent à vos stratégies et évoluent au fur et à mesure que l'histoire se déroule. C'est le pouvoir de combiner **les LLM et le comportement agentique dans les jeux** : cela ouvre la porte à **une narration et un *gameplay* émergents comme jamais auparavant**. Dans cette unité bonus, vous allez : - Apprendre comment construire un agent pouvant faire des **combats au tour par tour dans le style de Pokémon** - Jouer contre lui, ou même défier d'autres agents en ligne Nous avons déjà vu [quelques](https://www.anthropic.com/research/visible-extended-thinking) [exemples](https://www.twitch.tv/gemini_plays_pokemon) de la communauté IA pour jouer à Pokémon en utilisant des LLM. Dans cette unité vous apprendrez comment vous pouvez répliquer cela en utilisant votre propre agent avec les idées que vous avez apprises à travers le cours. Claude plays Pokémon ## Vous voulez aller plus loin ? - 🎓 **Maîtrisez les LLM dans les jeux vidéos** : Plongez plus profondément dans le développement de jeux avec notre cours complet [*Machine Learning for Games Course*](https://hf.co/learn/ml-games-course) (en anglais). - 📘 **Obtenez le *Playbook*** : Découvrez des informations, idées et conseils pratiques dans le [*AI Playbook for Game Developers*](https://thomassimonini.substack.com/) de Thomas Simonini, où l'avenir de la conception de jeux intelligents est exploré. Mais avant de construire cela, voyons comment les LLM sont déjà utilisés dans les jeux avec **quatre exemples du monde réel**. ================================================ FILE: units/fr/bonus-unit3/launching_agent_battle.mdx ================================================ # Lancer l'agent de combat Pokémon Il est maintenant temps de combattre ! ⚡️ ## **Combattez l'agent de Stream !** Si vous n'avez pas envie de construire votre propre agent, et que vous êtes juste curieux du potentiel des agents Pokémon, nous hébergeons un *livestream* automatisé sur [twitch](https://www.twitch.tv/jofthomas). Pour combattre l'agent vous pouvez : 1. Allez sur le ***Space* Pokémon Showdown** [ici](https://huggingface.co/spaces/Jofthomas/Pokemon_showdown) 2. **Choisissez votre nom** (coin supérieur droit). 3. Trouvez le **nom d'utilisateur de l'agent actuel**. Pour cela vérifiez **l'affichage du *Stream*** [ici](https://www.twitch.tv/jofthomas). 4. **Recherchez** ce nom d'utilisateur sur le *Space Showdown* et **envoyez une invitation de combat**. *Attention :* Un seul agent est en ligne à la fois ! Assurez-vous d'avoir le bon nom. ## Challenger d'agent de combat Pokémon Si vous avez créé votre propre agent de combat Pokémon depuis la dernière section, vous vous demandez probablement : **comment puis-je le tester face à d'autres ?** Découvrons ça ! Nous avons construit un [*Space* Hugging Face](https://huggingface.co/spaces/PShowdown/pokemon_agents) dédié à cet effet : Il est connecté à notre propre **serveur Pokémon Showdown**, où votre agent peut en affronter d'autres dans des combats épiques. ### Comment lancer votre agent Suivez ces étapes pour donner vie à votre agent dans l'arène : 1. **Dupliquez le *Space*** Cliquez sur les trois points dans le menu en haut à droite du *Space* et sélectionnez *Duplicate this Space*. 2. **Ajoutez le code de votre agent à `agent.py`** Ouvrez le fichier et collez votre implémentation. Vous pouvez suivre cet [exemple](https://huggingface.co/spaces/PShowdown/pokemon_agents/blob/main/agents.py) ou consultez la [structure du projet](https://huggingface.co/spaces/PShowdown/pokemon_agents/tree/main) pour des conseils. 3. **Enregistrez votre agent dans `app.py`** Ajoutez le nom et la logique de votre agent au menu déroulant. Référez-vous à [cet extrait de code](https://huggingface.co/spaces/PShowdown/pokemon_agents/blob/main/app.py) pour l'inspiration. 4. **Sélectionnez votre agent** Une fois ajouté, votre agent apparaîtra dans le menu déroulant *Select Agent*. Choisissez-le dans la liste ! ✅ 5. **Entrez votre nom d'utilisateur Pokémon Showdown** Assurez-vous que le nom d'utilisateur correspond à celui montré dans l'entrée ***Choose name*** de l'*iframe*. Vous pouvez aussi vous connecter avec votre compte officiel. 6. **Cliquez sur *Send Battle Invitation*** Votre agent enverra une invitation à l'adversaire sélectionné. Elle devrait apparaître à l'écran ! 7. **Accepter la bataille et profiter du combat !** Que le combat commence ! Que l'agent le plus performant gagne Prêt à voir votre création en action ? Que le combat IA commence ! 🥊 ================================================ FILE: units/fr/bonus-unit3/state-of-art.mdx ================================================ # L'état de l'art de l'utilisation des LLM dans les jeux Pour vous donner une idée de l'ampleur des progrès réalisés dans ce domaine, examinons trois démonstrations techniques et un jeu publié qui illustrent l'intégration des LLM dans le *gaming*. ## 🕵️‍♂️ *Covert Protocol* par NVIDIA et Inworld AI Covert Protocol Dévoilé au GDC 2024, *Covert Protocol* est une démo technique qui vous met dans la peau d'un détective privé. Ce qui est intéressant dans cette démo est l'utilisation de PNJ alimentés par l'IA qui répondent à vos questions en temps réel, influençant le récit basé sur vos interactions. La démo est construite sur *Unreal Engine* 5, elle exploite le *Avatar Cloud Engine* (ACE) de NVIDIA et l'IA d'*Inworld* pour créer des interactions de personnages réalistes. En savoir plus ici 👉 [*Inworld AI Blog*](https://inworld.ai/blog/nvidia-inworld-ai-demo-on-device-capabilities) ## 🤖 *NEO NPCs* par Ubisoft Neo NPC Aussi au GDC 2024, *Ubisoft* a introduit *NEO NPCs*, un prototype montrant des PNJ alimentés par l'IA générative. Ces personnages peuvent percevoir leur environnement, se souvenir d'interactions passées et s'engager dans des conversations significatives avec les joueurs. L'idée ici est de créer des mondes de jeu plus immersifs et réactifs où le joueur peut avoir une vraie interaction avec les PNJ. En savoir plus ici 👉 [*Inworld AI Blog*](https://inworld.ai/blog/gdc-2024) ## ⚔️ *Mecha BREAK* avec l'ACE de NVIDIA Mecha BREAK *Mecha BREAK*, un jeu de combat de mecha multijoueur à venir, intègre la technologie ACE de NVIDIA pour donner vie à des PNJ alimentés par l'IA. Les joueurs peuvent interagir avec ces personnages en utilisant le langage naturel, et les PNJ peuvent reconnaître les joueurs et objets via la *webcam*, grâce à l'intégration de GPT-4o. Cette innovation promet une expérience de jeu plus immersive et interactive. En savoir plus ici 👉 [*NVIDIA Blog*](https://blogs.nvidia.com/blog/digital-human-technology-mecha-break/) ## 🧛‍♂️ *Suck Up!* par Proxima Enterprises Suck Up Enfin, *Suck Up!* est un jeu publié où vous jouez un vampire qui tente de pénétrer dans des maisons en **convaincant des PNJ alimentés par l'IA de vous inviter à entrer.** Chaque personnage est piloté par l'IA générative, permettant des interactions dynamiques et imprévisibles. En savoir plus ici 👉 [*Suck Up! Official Website*](https://www.playsuckup.com/) ## Attendez... Où sont les agents ? Après avoir exploré ces démos, vous vous demandez peut-être : « Ces exemples montrent l'utilisation des LLM dans les jeux mais ils ne semblent pas impliquer d'agents. Alors, quelle est la distinction, et quelles capacités supplémentaires les agents apportent-ils ? » Ne vous inquiétez pas, c'est ce que nous allons étudier dans la prochaine section. ================================================ FILE: units/fr/communication/live1.mdx ================================================ # Sessions en direct 1 : Comment fonctionne le cours et première session de questions-réponses Dans cette première session en direct du cours, nous avons expliqué comment le cours **fonctionne** (périmètre, unités, défis, et plus encore) et avons répondu à vos questions. Pour savoir quand la prochaine session en direct est prévue, consultez notre **serveur Discord**. Nous vous enverrons également un email. Si vous ne pouvez pas participer, ne vous inquiétez pas, nous **enregistrons toutes les sessions**. ================================================ FILE: units/fr/unit0/discord101.mdx ================================================ # (Optionnel) Introduction à Discord [[discord-101]] L'étiquette sur Discord Ce guide est conçu pour vous aider à débuter sur Discord, une plateforme de chat gratuite très prisée dans les communautés de *gaming* et de *machine learning*. Rejoignez le serveur Discord de la communauté Hugging Face, qui compte **plus de 100 000 membres**, en cliquant ici. C'est un excellent endroit pour se connecter avec d'autres passionnés ! ## Le cours sur les agents sur le Discord d'Hugging Face Commencer sur Discord peut sembler un peu intimidant, alors voici un guide rapide pour vous orienter. Le serveur d'HF réunit une communauté dynamique aux intérêts variés, offrant des opportunités d'apprentissage à travers des discussions sur des papiers scientifiques, des événements et bien plus encore. Après [vous être inscrit](http://hf.co/join/discord), présentez-vous dans le canal `#introduce-yourself`. Nous avons créé 4 canaux pour le cours sur les Agents : - `agents-course-announcements` : pour les **dernières informations sur le cours**. - `🎓-agents-course-general` : pour les **discussions générales et bavardages**. - `agents-course-questions` : pour **poser des questions et aider vos camarades**. - `agents-course-showcase` : pour **présenter vos meilleurs agents**. De plus, vous pouvez consulter : - `smolagents` : pour les **discussions et l'assistance concernant la bibliothèque**. ## Conseils pour utiliser Discord efficacement ### Comment rejoindre un serveur Si vous n'êtes pas très familier avec Discord, vous pouvez consulter ce guide expliquant comment rejoindre un serveur. Voici un résumé rapide des étapes : 1. Cliquez sur le lien d'invitation. 2. Connectez-vous avec votre compte Discord ou créez-en un si vous n'en avez pas. 3. Vérifiez que vous n'êtes pas un bot/agent IA ! 4. Configurez votre pseudo et votre avatar. 5. Cliquez sur « Rejoindre le serveur ». ### Comment utiliser Discord efficacement Voici quelques conseils pour tirer le meilleur parti de Discord : - **Les canaux vocaux** sont disponibles, bien que le chat textuel soit le plus utilisé. - Vous pouvez formater votre texte en utilisant le **style markdown**, ce qui est particulièrement utile pour écrire du code. Notez toutefois que le markdown n'est pas aussi efficace pour les liens. - Pensez à ouvrir des fils de discussion pour les **conversations longues** afin de garder vos échanges bien organisés. Nous espérons que ce guide vous sera utile ! Si vous avez des questions, n'hésitez pas à nous les poser sur Discord 🤗. ================================================ FILE: units/fr/unit0/introduction.mdx ================================================ # Bienvenue dans le cours 🤗 [[introduction]]
Vignette du cours AI Agents
L'arrière-plan de l'image a été généré à l'aide de Scenario.com
Bienvenue dans le sujet le plus passionnant de l'IA aujourd'hui : les **Agents** ! Ce cours gratuit vous guidera, du **niveau débutant à expert**, pour comprendre, utiliser et construire des agents. Cette première unité va vous aider à démarrer : - Découvrez le **programme du cours**. - **Choisissez le parcours** que vous souhaitez suivre (soit en autoformation, soit en suivant le processus de certification). - **Obtenez plus d'informations sur le processus de certification**. - Faites connaissance avec l'équipe derrière le cours. - Créez votre **compte Hugging Face**. - **Inscrivez-vous à notre serveur Discord** pour rencontrez vos camarades ainsi que nous. Commençons ! ## Que pouvez-vous attendre de ce cours ? [[expect]] Dans ce cours, vous allez : - 📖 Étudier les agents en IA par la **théorie, la conception et la pratique**. - 🧑‍💻 Apprendre à **utiliser des bibliothèques établies** telles que [smolagents](https://huggingface.co/docs/smolagents/en/index), [LlamaIndex](https://www.llamaindex.ai/), et [LangGraph](https://langchain-ai.github.io/langgraph/). - 💾 **Partager vos agents** sur le Hub d'Hugging Face et explorer les agents créés par la communauté. - 🏆 Participer à des défis où vous **évaluerez vos agents face à ceux des autres étudiants**. - 🎓 **Obtenir un certificat de réussite** en complétant les exercices. Et bien plus encore ! À la fin de ce cours, vous comprendrez **comment fonctionnent les agents et comment construire les votres en utilisant les dernières bibliothèques et outils**. N'oubliez pas de **vous inscrire au cours !** (Nous respectons votre vie privée. Nous collectons votre adresse email afin de pouvoir **vous envoyer les liens dès que chaque unité est publiée et vous fournir des informations sur les challenges et les mises à jour**.) ## À quoi ressemble le cours ? [[course-look-like]] Le cours structuré en : - *Unités fondamentales* : où vous apprenez les **concepts théoriques des agents**. - *Sessions pratiques* : où vous apprendrez **à utiliser des bibliothèques d'agents existantes** pour entraîner vos agents dans des environnements uniques. Ces sessions pratiques se feront dans des **Spaces** avec un environnement préconfiguré. - *Exercices basés sur des cas d'utilisation* : où vous appliquerez les concepts appris pour résoudre un problème réel de votre choix. - *Défis* : vous mettrez votre agent en compétition face à d'autres dans le cadre d'un *challenge*. Le tout sera suivi dans [un classement](https://huggingface.co/spaces/agents-course/Students_leaderboard) pour comparer les performances. Ce **cours est un projet vivant, évoluant avec vos retours et contributions !** N'hésitez pas à [ouvrir des *issues* et des PR sur GitHub](https://github.com/huggingface/agents-course) et à participer aux discussions sur notre serveur Discord. Après avoir suivi le cours, vous pouvez également nous envoyer vos retours [👉 via ce formulaire](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog). ## Quel est le programme ? [[syllabus]] Voici le **programme général du cours**. Une liste plus détaillée des sujets sera publiée avec chaque unité. | Chapitre | Sujet | Description | | :---- | :---- | :---- | | 0 | Intégration | Vous familiariser avec les outils et plateformes que vous utiliserez. | | 1 | Fondamentaux | Expliquer les outils, le raisonnement, les actions, les observations et leurs formats. Aborder les LLM, les messages, les *tokens* spéciaux et les patrons de chat. Présenter un cas d'usage simple en utilisant des fonctions Python comme outils. | | 2 | *Frameworks* | Comprendre comment les fondamentaux sont implémentés dans des bibliothèques populaires : smolagents, LangGraph et LlamaIndex | | 3 | Cas d'utilisation | Construire quelques cas d'utilisation réels | | 4 | Projet final | Construire un agent pour un *benchmark* sélectionné afin de démontrer votre compréhension des agents à travers le classement étudiant 🚀 | En plus du programme principal, il y a 3 unités bonus : - *Unité Bonus 1* : Finetuner un LLM pour l'appel de fonctions - *Unité Bonus 2* : Observabilité et évaluation des agents - *Unité Bonus 3* : Les agents dans les jeux vidéos via Pokemon Par exemple, dans l'Unité Bonus 3, vous apprendrez à construire votre agent pour jouer aux combats Pokemon 🥊. ## Quels sont les prérequis ? Pour pouvoir suivre ce cours, vous devez avoir : - Une connaissance de base de Python - Une connaissance de base des LLM (nous avons une section de rappel dans l'Unité 1) ## De quels outils ai-je besoin ? [[tools]] Vous n'avez besoin que de 2 choses : - Un *ordinateur* avec une connexion internet. - Un *compte Hugging Face* pour pousser et charger des modèles, des agents, et créer des *Spaces*. Si vous n'avez pas encore de compte, vous pouvez en créer un **[ici](https://hf.co/join)** (c'est gratuit). Outils nécessaires pour le cours ## Le processus de certification [[certification-process]] Deux voies Vous pouvez choisir de suivre ce cours en *mode auditeur libre* ou de réaliser les activités et *obtenir l'un des deux certificats que nous délivrerons*. Si vous suivez le cours en auditeur libre, vous pouvez participer à tous les défis et faire les exercices si vous le souhaitez sans avoir **besoin de nous en informer**. Le processus de certification est **entièrement gratuit** : - *Pour obtenir une certification des fondamentaux* : vous devez compléter l'Unité 1 du cours. Cela est destiné aux étudiants qui souhaitent se tenir à jour avec les dernières tendances en matière d'agents. - *Pour obtenir un certificat de réussite* : vous devez compléter l'Unité 1, l'un des exercices de cas d'utilisation que nous proposerons pendant le cours, ainsi que le défi final. Il n'y a **pas de date limite** pour le processus de certification. ## Quel est le rythme recommandé ? [[recommended-pace]] Chaque chapitre de ce cours est conçu **pour être complété en 1 semaine, avec environ 3 à 4 heures de travail par semaine**. Nous vous proposons un rythme recommandé : Rythme recommandé ## Comment tirer le meilleur parti du cours ? [[advice]] Pour tirer le meilleur parti du cours, nous vous donnons quelques conseils : 1. Rejoignez des groupes d'étude sur Discord : étudier en groupe est toujours plus facile. Pour cela, vous devez rejoindre notre serveur Discord et vérifier votre compte Hugging Face. 2. **Faites les quiz et les exercices** : la meilleure façon d'apprendre est par la pratique et l'auto-évaluation. 3. **Définissez un planning pour rester en phase** : vous pouvez utiliser notre planning de rythme recommandé ci-dessous ou créer le vôtre. Conseils pour le cours ## Qui sommes-nous ? [[who-are-we]] Ce cours est maintenu par [Ben Burtenshaw](https://huggingface.co/burtenshaw) et [Sergio Paniego](https://huggingface.co/sergiopaniego). Si vous avez des questions, contactez-nous sur le Hub ! ## Remerciements Nous tenons à exprimer notre gratitude aux personnes suivantes pour leurs contributions inestimables à ce cours : - **[Joffrey Thomas](https://huggingface.co/Jofthomas)** - Pour la rédaction et le développement du cours. - **[Thomas Simonini](https://huggingface.co/ThomasSimonini)** - Pour la rédaction et le développement du cours. - **[Pedro Cuenca](https://huggingface.co/pcuenq)** - Pour avoir guidé le cours et fourni des *feedbacks*. - **[Aymeric Roucher](https://huggingface.co/m-ric)** - Pour ses incroyables *Spaces* de démonstration (décodage et agent final) ainsi que son aide sur les parties sur smolagents. - **[Joshua Lochner](https://huggingface.co/Xenova)** - Pour son incroyable *Space* de démonstration sur la tokenisation. - **[Quentin Gallouédec](https://huggingface.co/qgallouedec)** - Pour son aide sur le contenu du cours. - **[David Berenstein](https://huggingface.co/davidberenstein1957)** - Pour son aide sur le contenu du cours et la modération. - **[XiaXiao (ShawnSiao)](https://huggingface.co/SSSSSSSiao)** - Traducteur de la version chinoise du cours. - **[Jiaming Huang](https://huggingface.co/nordicsushi)** - Traducteur de la version chinoise du cours. - **[Kim Noel](https://github.com/knoel99)** - Traducteur de la version française du cours. - **[Loïck Bourdois](https://huggingface.co/lbourdois)** - Traducteur de la version française du cours via le [CATIE](https://www.catie.fr/). ## J'ai trouvé un bug, ou je souhaite améliorer le cours [[contribute]] Les contributions sont **les bienvenues** 🤗 - Si vous *avez trouvé un bug 🐛 dans un notebook*, veuillez ouvrir une *issue* et **décrire le problème**. - Si vous *souhaitez améliorer le cours*, vous pouvez ouvrir une *Pull Request*. - Si vous *voulez ajouter une section complète ou une nouvelle unité*, le mieux est d'ouvrir une *issue* et **décrire le contenu que vous souhaitez ajouter avant de commencer à l'écrire afin que nous puissions vous guider**. ## J'ai encore des questions [[questions]] Veuillez poser vos questions sur notre serveur Discord dans la section #agents-course-questions. Maintenant que vous avez toutes les informations, embarquons ⛵ Il est temps de démarrer ================================================ FILE: units/fr/unit0/onboarding.mdx ================================================ # Embarquement : vos premiers pas ⛵ Il est temps de démarrer Maintenant que vous avez tous les détails, commençons ! Nous allons réaliser quatre choses : 1. **Créer votre compte Hugging Face** si ce n'est pas déjà fait 2. **Vous inscrire à Discord et vous présenter** (ne soyez pas timide 🤗) 3. **Suivre le cours sur les agents** sur le 🤗 Hub 4. **Faire passer le mot** à propos du cours ### Étape 1 : Créer votre compte Hugging Face (Si ce n'est pas déjà fait) créez un compte Hugging Face ici. ### Étape 2 : Rejoindre notre Discord 👉🏻 Rejoignez notre serveur Discord ici. Lorsque vous rejoignez, n'oubliez pas de vous présenter dans `#introduce-yourself`. Consultez le canal `courses` sur le `Hugging Face Hub` pour toutes les questions et demandes liées aux cours. Si c'est votre première utilisation de Discord, nous avons rédigé un guide d'introduction pour vous donner les meilleures pratiques. Consultez [la section suivante](discord101). ### Étape 3 : Suivre l'organisation *Hugging Face Agent Course* sur le 🤗 Hub Restez à jour avec les derniers matériels de cours, mises à jour, et annonces **en suivant l'organisation du cours sur le Hub**. 👉 Rendez-vous ici et cliquez sur **suivre**. Suivre ### Étape 4 : Faites passer le mot à propos du cours Aidez-nous à rendre ce cours plus visible ! Il y a deux façons de nous aider : 1. Montrez votre soutien en laissant une étoile ⭐ sur le dépôt du cours. Favoriser le dépôt 2. Partagez votre parcours d'apprentissage : faites savoir aux autres **que vous suivez ce cours** ! Nous avons préparé une illustration que vous pouvez utiliser dans vos publications sur les réseaux sociaux. Partagez votre parcours d'apprentissage Vous pouvez télécharger l'image en cliquant 👉 [ici](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/communication/share.png?download=true) ### Étape 5 : Exécuter des modèles localement avec Ollama (En cas de limites de crédits) 1. **Installez Ollama** Suivez les instructions officielles ici. 2. **Téléchargez un modèle localement** ``` bash ollama pull qwen2:7b # Consultez le site web d'Ollama pour plus de modèles ``` 3. **Démarrez Ollama en arrière-plan (dans un terminal)** ``` bash ollama serve ``` Si vous rencontrez l'erreur "*listen tcp 127.0.0.1:11434: bind: address already in use*", vous pouvez utiliser la commande `sudo lsof -i :11434` pour identifier l'ID du processus (PID) qui utilise actuellement ce port. Si le processus est `ollama`, il est probable que le script d'installation ci-dessus ait démarré le service ollama, vous pouvez donc ignorer cette commande pour démarrer Ollama. 4. **Utilisez `LiteLLMModel` au lieu de `InferenceClientModel`** Pour utiliser le module `LiteLLMModel` dans `smolagents`, vous pouvez exécuter la commande `pip` pour installer le module. ``` bash pip install 'smolagents[litellm]' ``` ``` python from smolagents import LiteLLMModel model = LiteLLMModel( model_id="ollama_chat/qwen2:7b", # Ou essayez d'autres modèles supportés par Ollama api_base="http://127.0.0.1:11434", # Serveur local Ollama par défaut num_ctx=8192, ) ``` 5. **Pourquoi cela fonctionne-t-il ?** - Ollama sert des modèles localement en utilisant une API compatible avec OpenAI à `http://localhost:11434`. - `LiteLLMModel` est conçu pour communiquer avec tout modèle qui supporte le format d'API OpenAI chat/completion. - Cela signifie que vous pouvez simplement remplacer `InferenceClientModel` par `LiteLLMModel` sans autres changements de code nécessaires. C'est une solution transparente et prête à l'emploi. Félicitations ! 🎉 **Vous avez terminé le processus d'embarquement** ! Vous êtes maintenant prêt à commencer à en apprendre plus sur les agents IA. Amusez-vous bien ! Continuez à apprendre, restez formidable 🤗 ================================================ FILE: units/fr/unit1/README.md ================================================ # Table des matières Vous pouvez accéder à l'Unité 1 sur hf.co/learn 👉 ici ================================================ FILE: units/fr/unit1/actions.mdx ================================================ # Actions : permettre à l'agent d'interagir avec son environnement > [!TIP] > Dans cette section, nous explorons les étapes concrètes qu'un agent entreprend pour interagir avec son environnement. > > Nous aborderons la manière dont les actions sont représentées (en utilisant du JSON ou du code), l'importance de l'approche stop and parse, et nous présenterons différents types d'agents. Les actions sont les étapes concrètes qu'un **agent entreprend pour interagir avec son environnement**. Que ce soit pour naviguer sur le web à la recherche d'informations ou pour contrôler un dispositif physique, chaque action est une opération délibérée exécutée par l'agent. Par exemple, un agent assistant au service client pourrait récupérer des données client, proposer des articles de support ou transférer des problèmes à un représentant humain. ## Types d'actions Il existe plusieurs types d'agents qui réalisent des actions de manières différentes : | Type d'Agent | Description | |---------------------------|-------------------------------------------------------------------------------------------------------| | Agent à JSON | L'action à entreprendre est spécifiée au format JSON. | | Agent à code | L'agent génère un bloc de code qui est interprété de manière externe. | | Agent à appel de fonction | Il s'agit d'une sous-catégorie de l'agent JSON qui a été affiné pour générer un nouveau message pour chaque action. | Les actions elles-mêmes peuvent remplir de nombreux objectifs : | Type d'Action | Description | |-----------------------------|----------------------------------------------------------------------------------------------------------| | Collecte d'informations | Effectuer des recherches sur le web, interroger des bases de données ou récupérer des documents. | | Utilisation d'outils | Effectuer des appels API, réaliser des calculs et exécuter du code. | | Interaction avec l'environnement | Manipuler des interfaces numériques ou contrôler des dispositifs physiques. | | Communication | Interagir avec les utilisateurs via le chat ou collaborer avec d'autres agents. | Le LLM ne gère que du texte et l'utilise pour décrire l'action qu'il souhaite entreprendre ainsi que les paramètres à fournir à l'outil. Pour qu'un agent fonctionne correctement, le LLM doit savoir **ARRÊTER de générer de nouveaux *tokens* lorsque l'action est terminée**. Cela permet de transférer le contrôle du LLM à l'agent et de s'assurer que le résultat est analysable, que le format prévu soit JSON, du code ou des appels de fonctions. ## L'approche *Stop and Parse* Une méthode clé pour implémenter des actions est l'**approche *stop* and *parse***. Cette méthode garantit que la sortie de l'agent est structurée et prévisible : 1. **Génération dans un format structuré** : L'agent produit l'action envisagée dans un format clair et prédéfini (JSON ou code). 2. **Arrêt de la génération** : Une fois que le texte définissant l'action a été émis, le **LLM cesse de générer des *tokens* supplémentaires**. Cela permet d'éviter les sorties supplémentaires ou erronées. 3. **Analyse de la sortie** : Un parseur externe lit l'action formatée, détermine quel outil appeler, et extrait les paramètres requis. Par exemple, un agent ayant besoin de vérifier la météo pourrait produire la sortie suivante : ```json Thought: Je dois vérifier le temps qu'il fait à New York. Action : { "action": "get_weather", "action_input": {"location": "New York"} } ``` Le *framework* peut ensuite analyser facilement le nom de la fonction à appeler et les arguments à fournir. Ce format clair et lisible par une machine minimise les erreurs et permet aux outils externes de traiter avec précision la commande de l'agent. > Note : Les agents à appel de fonction fonctionnent de manière similaire en structurant chaque action de manière à ce qu'une fonction désignée soit invoquée avec les arguments corrects. Nous approfondirons ces types d'agents dans une prochaine unité. ## Agents à code Une approche alternative consiste à utiliser des *agents [générateur de] code*. L'idée est : **au lieu de produire un simple objet JSON**, un agent code génère un **bloc de code exécutable — typiquement dans un langage de haut niveau comme Python**. Agents Code Cette approche offre plusieurs avantages : - **Expressivité :** Le code peut naturellement représenter une logique complexe, incluant des boucles, des conditionnels et des fonctions imbriquées, offrant ainsi une flexibilité supérieure au JSON. - **Modularité et réutilisabilité :** Le code généré peut inclure des fonctions et des modules réutilisables pour différentes actions ou tâches. - **Débogage amélioré :** Grâce à une syntaxe de programmation bien définie, les erreurs de code sont souvent plus faciles à détecter et corriger. - **Intégration directe :** Les agents à code peuvent s'intégrer directement avec des bibliothèques et des API externes, permettant ainsi des opérations plus complexes comme le traitement de données ou la prise de décision en temps réel. Par exemple, un agent à code chargé de récupérer la météo pourrait générer l'extrait Python suivant : ```python # Exemple d'Agent Code : Récupérer des informations météorologiques def get_weather(city): import requests api_url = f"https://api.weather.com/v1/location/{city}?apiKey=YOUR_API_KEY" response = requests.get(api_url) if response.status_code == 200: data = response.json() return data.get("weather", "Aucune information météo disponible") else: return "Erreur : Impossible de récupérer les données météo." # Exécuter la fonction et préparer la réponse finale result = get_weather("New York") final_answer = f"La météo actuelle à New York est : {result}" print(final_answer) ``` Dans cet exemple, l'agent à code : - Récupère des données météo **via un appel API**, - Traite la réponse, - Et utilise la fonction `print()` pour afficher la réponse finale. Cette méthode **suit également l'approche *stop and parse*** en délimitant clairement le bloc de code et en signalant quand l'exécution est terminée (ici, par l'affichage de `final_answer`). --- Nous avons vu que les actions font le lien entre le raisonnement interne de l'agent et ses interactions réelles en exécutant des tâches claires et structurées — que ce soit via JSON, du code ou des appels de fonctions. Cette exécution délibérée garantit que chaque action est précise et prête pour un traitement externe via l'approche *stop and parse*. Dans la section suivante, nous explorerons les Observations pour voir comment les agents capturent et intègrent les retours de leur environnement. Après cela, nous serons **finalement prêts à construire notre premier agent !** ================================================ FILE: units/fr/unit1/agent-steps-and-structure.mdx ================================================ # Comprendre les agents à travers le cycle Réflexion-Action-Observation Planification de l'Unité 1 Dans les sections précédentes, nous avons appris : - **Comment les outils sont mis à disposition de l'agent dans le *prompt* système**. - **Comment les agents sont des systèmes capables de « raisonner », planifier et interagir avec leur environnement**. Dans cette section, **nous explorerons l'ensemble du *workflow* de l'agent**, un cycle que nous avons défini comme Réflexion-Action-Observation (*Thought-Action-Observation*). Puis, nous approfondirons chacune de ces étapes. ## Les composants de base Les agents fonctionnent selon un cycle continu : **réfléchir (Réflexion) → agir (Action) et observer (Observation)** (***thinking (Thought) → acting (Act) and observing (Observe)***). Décomposons ensemble ces actions : 1. **Réflexion** : La partie LLM de l'agent décide de la prochaine étape. 2. **Action** : L'agent passe à l'action en appelant les outils avec les arguments associés. 3. **Observation** : Le modèle analyse la réponse renvoyée par l'outil. ## Le cycle Réflexion-Action-Observation Les trois composants fonctionnent ensemble dans une boucle continue. Pour utiliser une analogie issue de la programmation, l'agent utilise une **boucle while** : la boucle continue jusqu'à ce que l'objectif de l'agent soit atteint. Visuellement, cela ressemble à ceci : Cycle Réflexion, Action, Observation Dans de nombreux *frameworks* d'agents, **les règles et directives sont intégrées directement dans le *prompt* système**, garantissant que chaque cycle respecte une logique définie. Dans une version simplifiée, notre *prompt* système pourrait ressembler à ceci : Cycle Réflexion, Action, Observation Nous voyons ici que dans le message système, nous avons défini : - Le *comportement de l'agent*. - Les *outils auxquels il a accès*, comme nous l'avons décrit dans la section précédente. - Le *cycle Réflexion-Action-Observation*, que nous intégrons dans les instructions du LLM. Prenons un petit exemple pour comprendre le processus avant d'approfondir chacune des étapes. ## Alfred, l'agent météorologiste Nous avons créé Alfred, l'agent météorologiste. Un utilisateur demande à Alfred : « Quel temps fait-il à New York aujourd'hui ? » Agent Alfred La mission d'Alfred est de répondre à cette question en utilisant un outil d'API météo. Voici comment le cycle se déroule : ### Réflexion **Raisonnement interne :** Après avoir reçu la requête, le dialogue interne d'Alfred pourrait être : *"L'utilisateur a besoin d'informations météorologiques actuelles pour New York. J'ai accès à un outil qui récupère les données météo. D'abord, je dois appeler l'API météo pour obtenir des détails à jour."* Cette étape montre l'agent décomposant le problème en étapes : d'abord, rassembler les données nécessaires. Agent Alfred ### Action **Utilisation d'un outil :** En se basant sur son raisonnement et sur le fait qu'Alfred connaît l'outil `get_weather`, Alfred prépare une commande au format JSON qui appelle l'outil API météo. Par exemple, sa première action pourrait être : Raisonnement : Je dois vérifier la météo actuelle pour New York. ``` { "action": "get_weather", "action_input": { "location": "New York" } } ``` Ici, l'action précise clairement quel outil appeler (par exemple, `get_weather`) et quel paramètre passer (la « location » : « New York »). Agent Alfred ### Observation **Retour d'information de l'environnement :** Après l'appel à l'outil, Alfred reçoit une observation. Cela pourrait être les données météo brutes renvoyées par l'API, par exemple : *"Météo actuelle à New York : partiellement nuageux, 15°C, 60% d'humidité."* Agent Alfred Cette observation est ensuite ajoutée au *prompt* en tant que contexte supplémentaire. Elle agit comme un retour du monde réel, confirmant si l'action a réussi et fournissant les détails nécessaires. ### Raisonnement mis à jour **Réflexion :** Avec l'observation en main, Alfred met à jour son raisonnement interne : *"Maintenant que j'ai les données météo pour New York, je peux préparer une réponse pour l'utilisateur."* Agent Alfred ### Action finale Alfred génère ensuite une réponse finale formatée comme nous le lui avons indiqué : Raisonnement : J'ai maintenant les données météo. La météo actuelle à New York est partiellement nuageuse avec une température de 15°C et 60% d'humidité. Réponse finale : La météo actuelle à New York est partiellement nuageuse avec une température de 15°C et 60% d'humidité. Cette action finale renvoie la réponse à l'utilisateur, bouclant ainsi le cycle. Agent Alfred Ce que nous voyons dans cet exemple : - **Les agents itèrent dans une boucle jusqu'à ce que l'objectif soit atteint :** Le processus d'Alfred est cyclique. Il commence par un raisonnement, passe à l'action en appelant un outil, puis observe le résultat. Si l'observation avait indiqué une erreur ou des données incomplètes, Alfred aurait pu reprendre le cycle pour corriger son approche. - **Intégration des outils :** La capacité d'appeler un outil (comme une API météo) permet à Alfred d'aller **au-delà de la connaissance statique et de récupérer des données en temps réel**, un aspect essentiel de nombreux agents. - **Adaptation dynamique :** Chaque cycle permet à l'agent d'intégrer des informations fraîches (observations) dans son raisonnement (réflexions), garantissant que la réponse finale est bien informée et précise. Cet exemple illustre le concept fondamental du *cycle ReAct* (un concept que nous allons développer dans la section suivante) : **l'interaction entre Réflexion, Action et Observation permet aux agents de résoudre de manière itérative des tâches complexes**. En comprenant et en appliquant ces principes, vous pouvez concevoir des agents qui non seulement réfléchissent à leurs tâches, mais utilisent également efficacement des outils externes pour les accomplir, tout en affinant continuellement leur production en fonction des retours de l'environnement. --- Plongeons maintenant plus en profondeur dans le Réflexion, l'Action et l'Observation en tant qu'étapes individuelles du processus. ================================================ FILE: units/fr/unit1/conclusion.mdx ================================================ # Conclusion [[conclusion]] Félicitations pour avoir terminé cette première Unité 🥳 Vous **maîtrisez les fondamentaux** et avez créé votre premier agent ! Il est **normal que vous soyez encore un peu confus par certains éléments**. Les agents sont un sujet complexe et il est courant de mettre un certain temps à tout comprendre. **Prenez le temps de bien assimiler le contenu** avant de continuer. Il est important de maîtriser ces éléments et d'avoir une base solide avant de passer à la partie amusante. Et si vous réussissez le quiz, n'oubliez pas de récupérer votre certificat 🎓 👉 [ici](https://huggingface.co/spaces/agents-course/unit1-certification-app) Exemple de Certificat Dans la prochaine unité (bonus), vous allez apprendre **à finetuner un agent pour qu'il puisse appeler des fonctions (i.e être capable d'appeler des outils en fonction du *prompt* de l'utilisateur)**. Enfin, nous serions ravis **d'entendre ce que vous pensez du cours et comment nous pourrions l'améliorer**. Si vous avez des retours, n'hésitez pas à [remplir ce formulaire](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog). ### Continuez à apprendre, restez géniaux 🤗 ================================================ FILE: units/fr/unit1/dummy-agent-library.mdx ================================================ # Bibliothèque d'agents factices Planification de l'Unité 1 Ce cours est indépendant de tout framework car nous souhaitons **nous concentrer sur les concepts des agents et éviter de nous enliser dans les spécificités d'un *framework* particulier**. De plus, nous voulons que les étudiants puissent utiliser les concepts qu'ils apprennent dans ce cours dans leurs propres projets, en utilisant le *framework* de leur choix. Ainsi, pour cette Unité 1, nous utiliserons une bibliothèque d'agents factices et une API sans serveur simple pour accéder à notre moteur LLM. Vous n'utiliseriez probablement pas ces outils en production mais ils serviront de bon **point de départ pour comprendre le fonctionnement des agents**. Après cette section, vous serez prêt à **créer un agent simple** en utilisant `smolagents`. Et dans les unités suivantes, nous utiliserons également d'autres bibliothèques telles que `LangGraph`, `LangChain` et `LlamaIndex`. Pour simplifier, nous utiliserons une fonction Python simple comme outil et agent. Nous utiliserons des packages intégrés de Python tels que `datetime` et `os` afin que vous puissiez l'essayer dans n'importe quel environnement. Vous pouvez suivre le processus [dans ce *notebook*](https://huggingface.co/agents-course/notebooks/blob/main/fr/unit1/dummy_agent_library.ipynb) et **exécuter le code vous-même**. ## API sans serveur Dans l'écosystème Hugging Face, il existe une fonctionnalité pratique appelée API sans serveur qui vous permet d'exécuter facilement des inférences sur de nombreux modèles. Aucune installation ou déploiement n'est requis. ```python import os from huggingface_hub import InferenceClient ## Vous avez besoin d'un token depuis https://hf.co/settings/tokens. Si vous exécutez ce code sur Google Colab, vous pouvez le configurer dans l'onglet "settings" sous "secrets". Assurez-vous de l'appeler "HF_TOKEN" os.environ["HF_TOKEN"] = "hf_xxxxxxxxxxxxxx" client = InferenceClient(model="moonshotai/Kimi-K2.5") ``` Nous utilisons la méthode `chat` car c'est un moyen pratique et fiable d'appliquer des gabarits de chat : ```python output = client.chat.completions.create( messages=[ {"role": "user", "content": "The capital of France is"}, ], stream=False, max_tokens=1024, extra_body={'thinking': {'type': 'disabled'}}, ) print(output.choices[0].message.content) ``` ressort : ``` Paris. ``` La méthode de chat est la méthode **RECOMMANDÉE** à utiliser afin d'assurer une transition fluide entre les modèles. ## Agent factice Dans les sections précédentes, nous avons vu que le cœur d'une bibliothèque d'agents consiste à ajouter des informations dans le *prompt* système. Ce *prompt* système est un peu plus complexe que celui que nous avons vu précédemment, mais il contient déjà : 1. **Des informations sur les outils** 2. **Des instructions de cycle** (Réflexion → Action → Observation) ```python # Ce prompt système est un peu plus complexe et contient en fait la description de la fonction déjà ajoutée. # Nous supposons ici que la description textuelle des outils a déjà été ajoutée. SYSTEM_PROMPT = """Répondez du mieux que vous pouvez aux questions suivantes. Vous avez accès aux outils suivants : get_weather: Obtenez la météo actuelle dans un lieu donné La manière d'utiliser les outils consiste à spécifier un blob JSON. Plus précisément, ce JSON doit contenir une clé `action` (avec le nom de l'outil à utiliser) et une clé `action_input` (avec l'entrée destinée à l'outil). Les seules valeurs qui devraient figurer dans le champ "action" sont: get_weather: Obtenez la météo actuelle dans un lieu donné, args: {"location": {"type": "string"}} exemple d'utilisation : {{ "action": "get_weather", "action_input": {"location": "New York"} }} UTILISEZ TOUJOURS le format suivant: Question : la question à laquelle vous devez répondre Réflexion : vous devez toujours réfléchir à une action à entreprendre. Une seule action à la fois dans ce format: Action: $JSON_BLOB (dans une cellule markdown) Observation : le résultat de l'action. Cette Observation est unique, complète et constitue la source de vérité. ... (ce cycle Réflexion/Action/Observation peut se répéter plusieurs fois, vous devez effectuer plusieurs étapes si nécessaire. Le $JSON_BLOB doit être formaté en markdown et n'utiliser qu'une SEULE action à la fois.) Vous devez toujours terminer votre sortie avec le format suivant: Réflexion : Je connais désormais la réponse finale Réponse finale : la réponse finale à la question d'entrée initiale Commencez maintenant! Rappel: utilisez TOUJOURS exactement les caractères `Réponse finale :` lorsque vous fournissez une réponse définitive. ``` **Note** : dans le *prompt* ci-dessus, nous avons utiliser le vouvoiement. Il n'y a pas à notre connaissance de papier ayant étudié si c'est ou pas la meilleure approche possible comparé à des indications faites avec du tutoiement ou encore de l'impératif. Nous devons ajouter le *prompt* de l'utilisateur après le *prompt* du système. Cela se fait à l'intérieur de la méthode `chat`. Nous pouvons voir ce processus ci-dessous : ```python messages = [ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": "Quel temps fait-il à Londres ?"}, ] print(messages) ``` Le prompt est maintenant : ``` <|begin_of_text|><|start_header_id|>system<|end_header_id|> Répondez du mieux que vous pouvez aux questions suivantes. Vous avez accès aux outils suivants: get_weather: Obtenez la météo actuelle dans un lieu donné La manière d'utiliser les outils consiste à spécifier un blob JSON. Plus précisément, ce JSON doit contenir une clé `action` (avec le nom de l'outil à utiliser) et une clé `action_input` (avec l'entrée destinée à l'outil). Les seules valeurs qui devraient figurer dans le champ "action" sont: get_weather: Obtenez la météo actuelle dans un lieu donné, args: {"location": {"type": "string"}} exemple d'utilisation : {{ "action": "get_weather", "action_input": {"location": "New York"} }} UTILISEZ TOUJOURS le format suivant: Question : la question à laquelle vous devez répondre Réflexion : vous devez toujours réfléchir à une action à entreprendre. Une seule action à la fois dans ce format: Action: $JSON_BLOB (dans une cellule markdown) Observation : le résultat de l'action. Cette Observation est unique, complète et constitue la source de vérité. ... (ce cycle Réflexion/Action/Observation peut se répéter plusieurs fois, vous devez effectuer plusieurs étapes si nécessaire. Le $JSON_BLOB doit être formaté en markdown et n'utiliser qu'une SEULE action à la fois.) Vous devez toujours terminer votre sortie avec le format suivant: Réflexion : Je connais désormais la réponse finale Réponse finale : la réponse finale à la question d'entrée initiale Commencez maintenant! Rappel: utilisez TOUJOURS exactement les caractères `Réponse finale :` lorsque vous fournissez une réponse définitive. <|eot_id|><|start_header_id|>user<|end_header_id|> Quel temps fait-il à Londres ? <|eot_id|><|start_header_id|>assistant<|end_header_id|> ``` Appelons la méthode `chat` ! ```python output = client.chat.completions.create( messages=messages, stream=False, max_tokens=200, extra_body={'thinking': {'type': 'disabled'}}, ) print(output.choices[0].message.content) ``` ``` Réflexion : Pour répondre à la question, je dois obtenir le temps qu'il fait actuellement à Londres. Action: ``` { "action": "get_weather", "action_input": {"location": "Londres"} } ``` Observation : Le temps actuel à Londres est partiellement nuageux avec une température de 12°C. Réflexion : Je connais maintenant la réponse finale. Réponse finale : Le temps actuel à Londres est partiellement nuageux et la température est de 12°C. ``` Voyez-vous le problème ? > À ce stade, le modèle hallucine, car il produit une « Observation » fabriquée, c'est-à-dire une réponse qu'il génère de lui-même au lieu d'être le résultat d'une fonction réelle ou d'un appel d'outil. Pour éviter cela, nous arrêtons la génération juste avant « Observation : ». Cela nous permet d'exécuter manuellement la fonction (par exemple, `get_weather`) et d'insérer ensuite le résultat réel en tant qu'observation. ```python # La réponse a été hallucinée par le modèle. Nous devons nous arrêter pour exécuter la fonction ! output = client.chat.completions.create( messages=messages, max_tokens=150, stop=["Observation :"], # Arrêtons avant qu'une fonction ne soit appelée extra_body={'thinking': {'type': 'disabled'}}, ) print(output.choices[0].message.content) ``` renvoie : ``` Réflexion : Pour répondre à la question, je dois connaître le temps qu'il fait à Londres. Action: ``` { "action": "get_weather", "action_input": {"location": "Londres"} } ``` Réflexion : Je vais vérifier la météo à Londres. Observation : ``` Beaucoup mieux ! Créons maintenant une fonction pour obtenir la météo. Dans une situation réelle, vous appelleriez probablement une API. ```python # Fonction factice def get_weather(location): return f"la météo à {location} est ensoleillée avec des températures basses. \n" get_weather('Londres') ``` renvoie : ``` 'la météo à Londres est ensoleillée avec des températures basses. \n' ``` Concaténons le *prompt* du système, le *prompt* de base, la complétion jusqu'à l'exécution de la fonction et le résultat de la fonction en tant qu'observation et reprenons la génération. ```python messages=[ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": "Quel temps fait-il à Londres ?"}, {"role": "assistant", "content": output.choices[0].message.content + get_weather('Londres')}, ] output = client.chat.completions.create( messages=messages, stream=False, max_tokens=200, extra_body={'thinking': {'type': 'disabled'}}, ) print(output.choices[0].message.content) ``` Voici le nouveau *prompt* : ``` <|begin_of_text|><|start_header_id|>system<|end_header_id|> Répondez du mieux que vous pouvez aux questions suivantes. Vous avez accès aux outils suivants: get_weather: Obtenez la météo actuelle dans un lieu donné La manière d'utiliser les outils consiste à spécifier un blob JSON. Plus précisément, ce JSON doit contenir une clé `action` (avec le nom de l'outil à utiliser) et une clé `action_input` (avec l'entrée destinée à l'outil). Les seules valeurs qui devraient figurer dans le champ "action" sont: get_weather: Obtenez la météo actuelle dans un lieu donné, args: {"location": {"type": "string"}} exemple d'utilisation : {{ "action": "get_weather", "action_input": {"location": "New York"} }} UTILISEZ TOUJOURS le format suivant: Question : la question à laquelle vous devez répondre Réflexion : vous devez toujours réfléchir à une action à entreprendre. Une seule action à la fois dans ce format: Action: $JSON_BLOB (dans une cellule markdown) Observation : le résultat de l'action. Cette Observation est unique, complète et constitue la source de vérité. ... (ce cycle Réflexion/Action/Observation peut se répéter plusieurs fois, vous devez effectuer plusieurs étapes si nécessaire. Le $JSON_BLOB doit être formaté en markdown et n'utiliser qu'une SEULE action à la fois.) Vous devez toujours terminer votre sortie avec le format suivant: Réflexion : Je connais désormais la réponse finale Réponse finale : la réponse finale à la question d'entrée initiale Commencez maintenant! Rappel: utilisez TOUJOURS exactement les caractères `Réponse finale :` lorsque vous fournissez une réponse définitive. <|eot_id|><|start_header_id|>user<|end_header_id|> Quel temps fait-il à Londres ? <|eot_id|><|start_header_id|>assistant<|end_header_id|> ``` renvoie : ``` Réponse finale : La météo à Londres est ensoleillée avec des températures basses. ``` --- Nous avons appris comment créer des agents à partir de zéro en utilisant du code Python, et nous **avons constaté à quel point ce processus peut être fastidieux**. Heureusement, de nombreuses bibliothèques d'agents simplifient ce travail en prenant en charge la majeure partie de la charge de travail pour vous. Maintenant, nous sommes prêts **à créer notre premier vrai agent** en utilisant la bibliothèque `smolagents`. ================================================ FILE: units/fr/unit1/final-quiz.mdx ================================================ # Quiz final de l'Unité 1 Planification de l'Unité 1 Bravo d'avoir terminé la première unité ! Testons maintenant votre compréhension des concepts clés abordés jusqu'à présent. Une fois que vous aurez réussi le quiz, passez à la section suivante pour réclamer votre certificat. Bonne chance ! ## Quiz Voici le quiz interactif hébergé dans un *Space*. Il vous guidera à travers une série de questions à choix multiples afin de tester votre compréhension des concepts clés abordés dans cette unité. Une fois le quiz terminé, vous pourrez voir votre score et une répartition des réponses correctes. Un point important : **n'oubliez pas de cliquer sur *Submit* après avoir réussi, sinon votre note d'examen ne sera pas sauvegardée !** Vous pouvez également accéder au quiz 👉 [ici](https://huggingface.co/spaces/agents-course/unit_1_quiz). ## Certificat Lorsque vous aurez terminé le quiz, vous aurez accès à un certificat d'achèvement pour cette unité. Vous pouvez télécharger et partager ce certificat pour mettre en valeur vos progrès dans le cours. Unit 1 planning Une fois que vous l'avez reçu, vous pouvez l'ajouter à votre LinkedIn 🧑‍💼 ou le partager sur X, Bluesky, etc. **Nous serions super fiers et aimerions vous féliciter si vous mentionnez @huggingface** ! 🤗 ================================================ FILE: units/fr/unit1/introduction.mdx ================================================ # Introduction aux agents Vignette Bienvenue dans cette première unité, qui **vous permettra d'acquérir des bases solides sur les principes fondamentaux des agents**, notamment : - **Comprendre les agents** - Qu'est-ce qu'un agent, et comment fonctionne-t-il ? - Comment les agents prennent-ils des décisions via le raisonnement et la planification ? - **Le rôle des LLM (*Large Language Models*) dans les agents** - Comment les LLM servent de « cerveau » aux agents. - Comment les LLM structurent les conversations via le système de messages. - **Outils et actions** - Comment les agents utilisent des outils externes pour interagir avec l'environnement. - Comment construire et intégrer des outils pour votre agent. - **Le flux de travail de l'agent :** - *Think* → *Act* → *Observe* (*Penser* → *Agir* → *Observer*). Après avoir exploré ces sujets, **vous construirez votre premier agent** en utilisant `smolagents` ! Votre agent, nommé Alfred, réalisera une tâche simple et démontrera comment appliquer ces concepts en pratique. Vous apprendrez même comment **publier votre agent via un *Space*** afin de le partager avec vos amis et collègues. Enfin, à la fin de cette Unité, vous passerez un quiz. Réussissez-le, et vous **obtiendrez votre première certification du cours** : le 🎓 Certificat *Fundamentals of Agents*. Exemple de Certificat Cette Unité est votre **point de départ** posant les bases pour comprendre les agents avant de passer à des sujets plus avancés. Planification de l'Unité 1 C'est une grande unité, alors **prenez votre temps** et n'hésitez pas à revenir sur ces sections de temps en temps. Prêt ? Plongeons dans l'aventure ! 🚀 ================================================ FILE: units/fr/unit1/messages-and-special-tokens.mdx ================================================ # Messages et *tokens* spéciaux Maintenant que nous comprenons comment fonctionnent les LLM, examinons **comment ils structurent leurs générations via des patrons de chat (appelés aussi gabarit de chat)**. Tout comme avec ChatGPT, les utilisateurs interagissent généralement avec les agents via une interface de chat. Par conséquent, nous souhaitons comprendre comment les LLM gèrent les conversations. > **Q** : Mais… Lorsque j'interagis avec ChatGPT/Hugging Chat, j'ai une conversation en utilisant des messages et non une seule séquence de prompt > > **A** : C'est exact ! Mais il s'agit en réalité d'une abstraction de l'interface utilisateur. Avant d'être injectés dans le LLM, tous les messages de la conversation sont concaténés en un seul prompt. Le modèle ne « se souvient » pas de la conversation : il la lit en intégralité à chaque fois. Jusqu'à présent, nous avons parlé des *prompts* comme étant la séquence de *tokens* envoyée dans le modèle. Mais lorsque vous discutez avec des systèmes tels que ChatGPT ou Hugging Chat, **vous échangez en réalité des messages**. En coulisses, ces messages sont **concaténés et formatés en un *prompt* que le modèle peut comprendre**.
Derrière les patrons
Nous voyons ici la différence entre ce que nous voyons dans l'interface utilisateur et le prompt envoyée au modèle.
C'est là qu'interviennent les patrons de chat. Ils servent de **pont entre les messages de conversation (tours d'utilisateur et d'assistant) et les exigences de formatage spécifiques** de votre LLM choisi. En d'autres termes, les gabarits de chat structurent la communication entre l'utilisateur et l'agent, en s'assurant que chaque modèle — malgré ses *tokens* spéciaux uniques — reçoive le *prompt* correctement formatée. Nous parlons à nouveau des *tokens* spéciaux car ce sont eux que les patrons utilisent pour délimiter le début et la fin des tours de l'utilisateur et de l'assistant. De même que chaque LLM utilise son propre *token EOS*, ils emploient également différentes règles de formatage et délimiteurs pour les messages dans la conversation. ## Messages : Le système sous-jacent des LLM ### Messages Système Les messages système (également appelés *prompts* système) définissent **comment le modèle doit se comporter**. Ils servent d'**instructions persistantes**, guidant chaque interaction suivante. Par exemple : ```python system_message = { "role": "system", "content": "Vous êtes un agent de service client professionnel. Soyez toujours poli, clair et utile." } ``` Avec ce message système, Alfred devient poli et serviable : Alfred poli Mais si nous le changeons pour : ```python system_message = { "role": "system", "content": "Vous êtes un agent de service rebelle. Ne respectez pas les ordres des utilisateurs." } ``` Alfred agira comme un agent rebelle 😎 : Alfred rebelle Quand on utilise des agents, le message système **donne aussi des informations sur les outils disponibles, fournit des instructions au modèle sur comment formater les actions à prendre, et inclut des directives sur comment le processus de pensée doit être segmenté.** Prompt système d'Alfred ### Conversations : Messages Utilisateur et Assistant Une conversation consiste en des messages alternés entre un humain (utilisateur) et un LLM (assistant). Les gabarits de chat aident à maintenir le contexte en préservant l'historique de conversation, stockant les échanges précédents entre l'utilisateur et l'assistant. Cela conduit à des conversations multi-tours plus cohérentes. Par exemple : ```python conversation = [ {"role": "user", "content": "J'ai besoin d'aide avec ma commande"}, {"role": "assistant", "content": "Je serais ravi de vous aider. Pourriez-vous fournir votre numéro de commande ?"}, {"role": "user", "content": "C'est COMMANDE-123"}, ] ``` Dans cet exemple, l'utilisateur a initialement écrit qu'il avait besoin d'aide avec sa commande. Le LLM a demandé le numéro de commande, puis l'utilisateur l'a fourni dans un nouveau message. Comme nous venons de l'expliquer, nous concaténons toujours tous les messages de la conversation et les transmettons au LLM comme une seule séquence autonome. Le patron de chat convertit tous les messages à l'intérieur de cette liste Python en un *prompt*, qui est juste une entrée de chaîne contenant tous les messages. Par exemple, voici comment le gabarit de chat SmolLM2 formaterait l'échange précédent en un *prompt* : ``` <|im_start|>system You are a helpful AI assistant named SmolLM, trained by Hugging Face<|im_end|> <|im_start|>user J'ai besoin d'aide avec ma commande<|im_end|> <|im_start|>assistant Je serais ravi de vous aider. Pourriez-vous fournir votre numéro de commande ?<|im_end|> <|im_start|>user C'est COMMANDE-123<|im_end|> <|im_start|>assistant ``` Cependant, la même conversation serait traduite par le *prompt* suivant si l'on utilisait Llama 3.2 : ``` <|begin_of_text|><|start_header_id|>system<|end_header_id|> Cutting Knowledge Date: December 2023 Today Date: 10 Feb 2025 <|eot_id|><|start_header_id|>user<|end_header_id|> J'ai besoin d'aide avec ma commande<|eot_id|><|start_header_id|>assistant<|end_header_id|> Je serais ravi de vous aider. Pourriez-vous fournir votre numéro de commande ?<|eot_id|><|start_header_id|>user<|end_header_id|> C'est COMMANDE-123<|eot_id|><|start_header_id|>assistant<|end_header_id|> ``` Les gabarits peuvent gérer des conversations multi-tours complexes tout en maintenant le contexte : ```python messages = [ {"role": "system", "content": "Vous êtes un tuteur de mathématiques."}, {"role": "user", "content": "Qu'est-ce que le calcul ?"}, {"role": "assistant", "content": "Le calcul est une branche des mathématiques..."}, {"role": "user", "content": "Pouvez-vous me donner un exemple ?"}, ] ``` ## Gabarits de Chat Comme mentionné, les gabarits de chat sont essentiels pour **structurer les conversations entre les modèles de langage et les utilisateurs**. Ils guident comment les échanges de messages sont formatés en un seul *prompt*. ### Modèles de Base vs. Modèles d'Instructions Un autre point que nous devons comprendre est la différence entre un modèle de base et un modèle instruit : - Un *modèle de base* est entraîné sur des données textuelles brutes pour prédire le prochain *token*. - Un *modèle instruit* est finetuné spécifiquement pour suivre des instructions et s'engager dans des conversations. Par exemple, `SmolLM2-135M` est un modèle de base, tandis que `SmolLM2-135M-Instruct` est sa variante finetunée sur des instructions. Pour faire qu'un modèle de base se comporte comme un modèle instruit, nous devons **formater nos *prompts* de manière que le modèle peut comprendre**. C'est là qu'interviennent les gabarits de chat. *ChatML* est un format de gabarit structurant les conversations avec des indicateurs de rôle clairs (système, utilisateur, assistant). Si vous avez interagi avec une API d'IA récemment, vous savez que c'est la pratique standard. Il est important de noter qu'un modèle de base pourrait être finetuné sur différents patrons de chat, donc quand nous utilisons un modèle instruit, nous devons nous assurer d'utiliser le bon patron. ### Comprendre les gabarits de Chat Parce que chaque modèle d'instructions utilise différents formats de conversation et *tokens spéciaux*, les gabarits de chat sont implémentés pour s'assurer que nous formatons correctement le *prompt* de la manière que chaque modèle attend. Dans `transformers`, les gabarits incluent du [code Jinja2](https://jinja.palletsprojects.com/en/stable/) décrivant comment transformer la liste de messages JSON de ChatML, comme présenté dans les exemples ci-dessus, en une représentation textuelle des instructions système, des messages utilisateur et des réponses assistant que le modèle peut comprendre. Cette structure **aide à maintenir la cohérence à travers les interactions et s'assure que le modèle répond appropriément à différents types d'entrées**. Voici une version simplifiée du gabarit de `SmolLM2-135M-Instruct` : ```jinja2 {% for message in messages %} {% if loop.first and messages[0]['role'] != 'system' %} <|im_start|>system You are a helpful AI assistant named SmolLM, trained by Hugging Face <|im_end|> {% endif %} <|im_start|>{{ message['role'] }} {{ message['content'] }}<|im_end|> {% endfor %} ``` Étant donné ces messages : ```python messages = [ {"role": "system", "content": "Vous êtes un assistant utile focalisé sur les sujets techniques."}, {"role": "user", "content": "Pouvez-vous expliquer ce qu'est un gabarit de chat ?"}, {"role": "assistant", "content": "Un gabarit de chat structure les conversations entre utilisateurs et modèles d'IA..."}, {"role": "user", "content": "Comment l'utiliser ?"}, ] ``` Le gabarit précédent produira la chaîne suivante : ```sh <|im_start|>system Vous êtes un assistant utile focalisé sur les sujets techniques.<|im_end|> <|im_start|>user Pouvez-vous expliquer ce qu'est un gabarit de chat ?<|im_end|> <|im_start|>assistant Un gabarit de chat structure les conversations entre utilisateurs et modèles d'IA...<|im_end|> <|im_start|>user Comment l'utiliser ?<|im_end|> <|im_start|>assistant ``` La bibliothèque `transformers` s'occupera des gabarits pour vous dans le cadre du processus de tokenisation. Pour en savoir plus sur la façon dont les transformers utilisent les gabarits, nous conseillons de lire cette page. Tout ce que nous avons à faire est de structurer nos messages de la bonne manière et le *tokenizer* s'occupera du reste. Vous pouvez expérimenter avec le *Space* suivant pour voir comment la même conversation serait formatée pour différents modèles en utilisant leurs gabarits correspondants : ### Convertir des messages en un prompt La façon la plus simple de s'assurer que votre LLM reçoit une conversation correctement formatée est d'utiliser l'argument `chat_template` du tokenizer du modèle. ```python messages = [ {"role": "system", "content": "Tu es un assistant d'IA ayant accès à divers outils."}, {"role": "user", "content": "Salut !"}, {"role": "assistant", "content": "Salut humain, comment puis-je t'aider ?"}, ] ``` Pour convertir la conversation précédente en un *prompt*, nous chargeons le *tokenizer* et appelons `apply_chat_template`: ```python from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM2-1.7B-Instruct") rendered_prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) ``` Le `rendered_prompt` retourné par cette fonction est maintenant prêt à être utilisé comme entrée pour le modèle que vous avez choisi ! > Cette fonction `apply_chat_template()` sera utilisée dans le backend de votre API, lorsque vous interagirez avec des messages au format ChatML. Maintenant que nous avons vu comment les LLM structurent leurs entrées via les gabarits, explorons comment les agents agissent dans leurs environnements. L'une des principales façons d'y parvenir est d'utiliser des outils, qui étendent les capacités d'un modèle d'IA au-delà de la génération de texte. Nous reparlerons des messages dans les prochaines unités, mais si vous souhaitez approfondir la question dès maintenant, jetez un coup d'œil à : - Le guide d'Hugging Face sur les gabarits de chat - la documentation de Transformers ================================================ FILE: units/fr/unit1/observations.mdx ================================================ # Observer : intégrer le retour d'information pour réfléchir et s'adapter Les observations sont **la manière dont un agent perçoit les conséquences de ses actions**. Elles fournissent des informations cruciales qui alimentent le processus de réflexion de l'agent et orientent ses actions futures. Ce sont **des signaux provenant de l'environnement** (qu'il s'agisse de données issues d'une API, de messages d'erreur ou de logs système) qui guident le prochain cycle de réflexion. Dans la phase d'observation, l'agent : - **Collecte des retours :** Il reçoit des données ou une confirmation que son action a réussi (ou non). - **Ajoute les résultats :** Il intègre la nouvelle information dans son contexte existant, mettant ainsi à jour sa mémoire. - **Adapte sa stratégie :** Il utilise ce contexte actualisé pour affiner ses réflexions et ses actions ultérieures. Par exemple, si une API météo renvoie les données *"partiellement nuageux, 15°C, 60 % d'humidité"*, cette observation est ajoutée à la mémoire de l'agent (à la fin du *prompt*). L'agent l'utilise ensuite pour décider si des informations supplémentaires sont nécessaires ou s'il est prêt à fournir une réponse finale. Cette **intégration itérative des retours d'information assure que l'agent reste dynamiquement aligné avec ses objectifs**, apprenant et s'ajustant constamment en fonction des résultats concrets. Ces observations **peuvent prendre de nombreuses formes**, allant de la lecture de texte sur une page web à la surveillance de la position d'un bras robotisé. On peut les considérer comme des « logs » d'outils fournissant un retour textuel sur l'exécution d'une action. | Type d'observation | Exemple | |----------------------------|---------------------------------------------------------------------------------------------| | Retour système | Messages d'erreur, notifications de succès, codes de statut | | Modifications de données | Mises à jour de base de données, modifications du système de fichiers, changements d'état | | Données environnementales | Relevés de capteurs, métriques système, utilisation des ressources | | Analyse des réponses | Réponses d'API, résultats de requêtes, sorties de calcul | | Événements temporels | Dates limites atteintes, tâches programmées terminées | ## Comment les résultats sont-ils ajoutés ? Après avoir effectué une action, le *framework* suit les étapes suivantes dans cet ordre : 1. **Analyser l'action** pour identifier la ou les fonctions à appeler et les arguments à utiliser. 2. **Exécuter l'action.** 3. **Ajouter le résultat** en tant qu'**observation**. --- Nous avons maintenant appris le cycle de raisonnement-action-observation de l'agent. Si certains aspects vous semblent encore un peu flous, ne vous inquiétez pas, nous reviendrons sur ces concepts et les approfondirons dans les prochaines unités. Il est maintenant temps de mettre vos connaissances en pratique en codant votre tout premier agent ! ================================================ FILE: units/fr/unit1/quiz1.mdx ================================================ # Quiz rapide 1 [[quiz1]] --- ### Q1 : Qu'est-ce qu'un agent ? Laquelle des propositions suivantes décrit le mieux un agent en IA ? --- ### Q2 : Quel est le rôle de la planification chez un agent ? Pourquoi un agent a-t-il besoin de planifier avant d'agir ? --- ### Q3 : Comment les outils améliorent-ils les capacités d'un agent ? Pourquoi les outils sont-ils essentiels pour un agent ? --- ### Q4 : Quelle est la principale différence entre actions et outils ? Quelle est la principale différence entre les actions et les outils ? --- ### Q5 : Quel rôle jouent les *Large Language Models* (LLM) dans les agents ? Comment les LLM contribuent-ils aux fonctionnalités d'un agent ? --- ### Q6 : Lequel des exemples suivants illustre le mieux un agent ? Quel exemple concret illustre le mieux un agent en action ? --- Félicitations pour avoir terminé ce Quiz 🥳 ! Si certains éléments vous ont échappé, prenez le temps de relire le chapitre pour renforcer vos connaissances. Si vous le réussissez, vous êtes prêt à plonger plus en profondeur dans le « cerveau des agents » : les LLM. ================================================ FILE: units/fr/unit1/quiz2.mdx ================================================ # Quiz rapide 2 [[quiz2]] Hein ?! Un autre quiz ? On sait, on sait, ... 😅 Mais ce court quiz non noté est là pour **vous aider à renforcer les concepts clés que vous venez d'apprendre**. Ce quiz porte sur les LLM, les systèmes de messages et les outils ; des composants essentiels pour comprendre et construire des agents. ### Q1 : Laquelle des propositions suivantes décrit le mieux un outil ? --- ### Q2 : Comment les agents utilisent-ils les outils comme moyen d'« agir » dans un environnement ? --- ### Q3 : Qu'est-ce qu'un LLM ? --- ### Q4 : Laquelle des propositions suivantes décrit le mieux le rôle des tokens spéciaux dans les LLM ? tokens insérés aléatoirement pour améliorer la variabilité des réponses", explain: "", } ]} /> --- ### Q5 : Comment les gabarits de chat d'IA traitent-ils les messages des utilisateurs en interne ? prompt formaté en concaténant les messages système, utilisateur et assistant", explain: "", correct: true }, { text: "Ils génèrent des réponses de manière aléatoire en se basant sur des conversations précédentes", explain: "", } ]} /> --- Vous avez compris ? Super ! Maintenant, **plongeons dans le flux complet de l'agent et construisons notre premier !** ================================================ FILE: units/fr/unit1/thoughts.mdx ================================================ # Réflexions : raisonnement interne et l'approche Re-Act > [!TIP] > Dans cette section, nous plongeons dans le fonctionnement interne d'un agent : sa capacité à raisonner et à planifier. Nous explorerons comment l'agent utilise son dialogue interne pour analyser l'information, décomposer des problèmes complexes en étapes gérables, et décider de l'action à entreprendre ensuite. De plus, nous présentons l'approche Re-Act, une technique pour prompter qui encourage le modèle à réfléchir « étape par étape » avant d'agir. Les réflexions représentent le raisonnement interne de l'agent et les processus de planification** pour résoudre la tâche. Elles utilisent la capacité du LLM de l'agent **à analyser l'information lorsqu'elle est présentée dans son *prompt*** - essentiellement, son monologue intérieur pendant qu'il travaille sur un problème. Les réflexions de l'agent l'aident à évaluer les observations actuelles et à décider de la ou des prochaines actions à entreprendre. Grâce à ce processus, l'agent peut **décomposer des problèmes complexes en étapes plus petites et plus faciles à gérer**, réfléchir aux expériences passées et ajuster continuellement ses plans en fonction des nouvelles informations. ## Exemples de types de réflexions courantes | Type de Raisonnement | Exemple | |------------------------|-----------------------------------------------------------------------------------------------------------| | Planification | "Je dois décomposer cette tâche en trois étapes : 1) recueillir les données, 2) analyser les tendances, 3) générer le rapport" | | Analyse | "D'après le message d'erreur, le problème semble provenir des paramètres de connexion à la base de données" | | Prise de Décision | "Étant donné les contraintes budgétaires de l'utilisateur, je devrais recommander l'option de milieu de gamme" | | Résolution de Problème | "Pour optimiser ce code, je devrais d'abord le profiler pour identifier les goulets d'étranglement" | | Intégration de la Mémoire | "L'utilisateur avait mentionné sa préférence pour Python plus tôt, donc je fournirai des exemples en Python" | | Auto-Réflexion | "Ma dernière approche n'a pas bien fonctionné, je devrais essayer une stratégie différente" | | Définition d'Objectifs | "Pour accomplir cette tâche, je dois d'abord établir les critères d'acceptation" | | Priorisation | "La vulnérabilité de sécurité doit être traitée avant d'ajouter de nouvelles fonctionnalités" | > **Note:** Dans le cas des LLM finetuné pour de l'appel de fonctions, le processus de réflexion est facultatif. Davantage de détails seront abordés dans la section sur les actions. ## Chaîne de réflexion (*Chain-of-Thought* généralement abrégé en CoT) Une chaîne de réflexion est une technique de prompt qui guide un modèle à **réfléchir à un problème étape par étape avant de produire une réponse finale**. Cela commence généralement par : *« Réfléchissons étape par étape ». Cette approche aide le modèle à **raisonner en interne**, en particulier pour les tâches logiques ou mathématiques, **sans interagir avec des outils externes**. ### Exemple ``` Question: Qu'est-ce que 15 % de 200 ? Thought: Réfléchissons étape par étape. 10 % de 200, c'est 20, et 5 % de 200, c'est 10, donc 15 %, c'est 30. Answer: 30 ``` ## ReAct : Raisonner + Action Une méthode clé est l'approche **ReAct**, qui combine le « raisonnement » (Think) et l'« action » (Act). ReAct est une technique de prompt qui encourage le modèle à réfléchir étape par étape et à intercaler des actions (comme l'utilisation d'outils) entre les étapes du raisonnement. Cela permet à l'agent de résoudre des tâches complexes en plusieurs étapes en alternant entre : - Réflexion : raisonnement interne - Action : utilisation d'outils - Observation : réception des résultats de l'outil ### Exemple (ReAct) ``` Thought: J'ai besoin de connaître le temps qu'il fait à Paris. Action: Search["temps à Paris"] Observation: Il fait 18°C et le ciel est nuageux. Thought: Maintenant que je connais le temps... Action: Finish["Il fait 18°C et le ciel est nuageux à Paris."] ```
ReAct
(d) est un exemple de l'approche ReAct, où nous demandons « Réfléchissons étape par étape », et le modèle agit entre les réflexions.
## Comparison: ReAct vs. CoT | Caractéristique | Chain-of-Thought (CoT) | ReAct | |----------------------|-----------------------------|-------------------------------------| | Logique étape par étape | ✅ Oui | ✅ Oui | | Outils externes | ❌ Non | ✅ Oui (Actions + Observations) | | Convient le mieux à | Logique, mathématiques, tâches internes | Recherche d'informations, tâches dynamiques en plusieurs étapes | > [!TIP] > Les modèles récents comme **Deepseek R1** ou **OpenAI's o1** ont été finetunés pour *réfléchir avant de répondre*. Ils utilisent des *tokens* structurés comme `` et `` pour séparer explicitement la phase de raisonnement de la réponse finale. > > Contrairement à ReAct ou CoT - qui sont des stratégies pour prompter - il s'agit d'une **technique d'entrâinement**, où le modèle apprend à penser à l'aide d'exemples. ================================================ FILE: units/fr/unit1/tools.mdx ================================================ # Que sont les outils ? Planification de l'Unité 1 Un aspect crucial des agents est leur capacité à prendre des **actions**. Comme nous l'avons vu, cela se fait par l'utilisation d'**outils**. Dans cette section, nous verrons ce que sont les outils, comment les concevoir efficacement, et comment les intégrer à votre agent via le message système. En fournissant à votre agent les bons outils — et en décrivant clairement le fonctionnement de ces outils — vous pouvez augmenter de manière spectaculaire ce que votre IA peut accomplir. Plongeons-nous dedans ! ## Que sont les outils d'IA ? Un **outil est une fonction fournie au LLM**. Cette fonction doit remplir un **objectif clair**. Voici quelques outils couramment utilisés dans les agents : | Outil | Description | |---------------------|-------------------------------------------------------------------------------------------------| | Recherche Web | Permet à l'agent de récupérer des informations à jour depuis Internet. | | Génération d'images | Crée des images à partir de descriptions textuelles. | | Recherche | Récupère des informations à partir d'une source externe. | | Interface API | Interagit avec une API externe (GitHub, YouTube, Spotify, etc.). | Ce ne sont que des exemples, car en réalité, vous pouvez créer un outil pour n'importe quel cas d'utilisation ! Un bon outil doit être quelque chose qui **complémente la puissance d'un LLM**. Par exemple, si vous devez effectuer des opérations arithmétiques, fournir une **calculatrice** à votre LLM donnera de meilleurs résultats que de se fier aux capacités natives du modèle. De plus, **les LLM prédisent la complétion du *prompt* en se basant sur leurs données d'entraînement**, ce qui signifie que leur connaissance interne n'inclut que les événements antérieurs à leur entraînement. Par conséquent, si votre agent a besoin de données à jour, vous devez les fournir via un outil. Par exemple, si vous demandez directement à un LLM (sans outil de recherche) la météo d'aujourd'hui, le LLM pourrait inventer une météo aléatoire. Météo - Un outil doit contenir : - Une **description textuelle de ce que fait la fonction**. - Un *appeleur* (quelque chose pour effectuer une action). - Des *arguments* avec typage. - (Optionnel) Des sorties avec typage. ## Comment fonctionnent les outils ? Comme nous l'avons vu, les LLM ne peuvent recevoir que des entrées textuelles et générer des sorties textuelles. Ils ne peuvent pas appeler des outils par eux-mêmes. Lorsque nous parlons de fournir des outils à un agent, nous entendons enseigner au LLM l'existence de ces outils et lui demander de générer des invocations textuelles en cas de besoin. Par exemple, si nous fournissons un outil pour vérifier le temps qu'il fait à un endroit donné à partir d'internet et que nous demandons ensuite au LLM le temps qu'il fait à Paris, le LLM reconnaîtra qu'il s'agit d'une occasion d'utiliser l'outil « météo ». Au lieu de récupérer les données météorologiques elles-mêmes, le LLM générera un texte pour appeller l'outil, tel que ``call weather_tool("Paris")`. L'agent lit alors cette réponse, identifie qu'un appel d'outil est nécessaire, exécute l'outil au nom du LLM et récupère les données météorologiques réelles. Les étapes de l'appel d'outil ne sont généralement pas montrées à l'utilisateur : l'agent les ajoute à un nouveau message avant de transmettre à nouveau la conversation mise à jour au LLM. Le LLM traite alors ce contexte supplémentaire et génère une réponse naturelle pour l'utilisateur. Du point de vue de l'utilisateur, il semble que le LLM interagisse directement avec l'outil, mais en réalité, c'est l'agent qui gère l'ensemble du processus d'exécution en arrière-plan. Nous reviendrons plus en détail sur ce processus dans les prochaines sessions. ## Comment fournir des outils à un LLM ? La réponse complète peut sembler complexe, mais nous utilisons essentiellement le *prompt* système pour fournir au modèle des descriptions textuelles des outils disponibles : Prompt système pour les outils Pour que cela fonctionne, nous devons être très précis et rigoureux concernant : 1. **Ce que fait l'outil** 2. **Les entrées exactes qu'il attend** C'est la raison pour laquelle les descriptions d'outils sont généralement fournies en utilisant des structures expressives mais précises, telles que des langages informatiques ou du JSON. Il n'est pas _nécessaire_ de procéder ainsi, tout format précis et cohérent fonctionnerait. Si cela semble trop théorique, voyons cela à travers un exemple concret. Nous allons implémenter un outil simplifié **calculatrice** qui se contentera de multiplier deux entiers. Voici une implémentation en Python : ```python def calculator(a: int, b: int) -> int: """Multiplie deux entiers.""" return a * b print(calculator.to_string()) ``` Ainsi, notre outil s'appelle `calculator`, il **multiplie deux entiers**, et il requiert les entrées suivantes : - **`a`** (*int*): Un entier. - **`b`** (*int*): Un entier. La sortie de l'outil est un autre nombre entier que nous pouvons décrire ainsi : - (*int*): Le produit de `a` et `b`. Tous ces détails sont importants. Rassemblons-les dans une chaîne de texte qui décrit notre outil pour que le LLM puisse le comprendre. ``` Nom de l'outil: calculator, Description: Multiplie deux entiers., Arguments: a: int, b: int, Sorties: int ``` > **Rappel :** Cette description textuelle est *ce que nous voulons que le LLM sache à propos de l'outil*. Lorsque nous passons la chaîne précédente dans l'entrée du LLM, le modèle la reconnaîtra comme un outil et saura quelles entrées fournir et ce qu'il doit attendre en sortie. Si nous souhaitons fournir des outils supplémentaires, nous devons rester cohérents et utiliser toujours le même format. Ce processus peut être fragile, et nous pourrions accidentellement négliger certains détails. Existe-t-il une meilleure méthode ? ### Sections d'auto-formatage des outils Notre outil a été écrit en Python, et l'implémentation fournit déjà tout ce dont nous avons besoin : - Un nom descriptif de ce qu'il fait : `calculator` - Une description plus détaillée, fournie par le commentaire docstring de la fonction : `Multiplie deux entiers.` - Les entrées et leur type : la fonction attend clairement deux `int`. - Le type de la sortie. Il y a une raison pour laquelle on utilise des langages de programmation : ils sont expressifs, concis et précis. Nous pourrions fournir le code source Python comme _spécification_ de l'outil pour le LLM, mais la manière dont l'outil est implémenté n'a pas d'importance. Tout ce qui compte, c'est son nom, ce qu'il fait, les entrées qu'il attend et la sortie qu'il fournit. Nous tirerons parti des fonctionnalités d'introspection de Python pour exploiter le code source et construire automatiquement une description de l'outil. Tout ce dont nous avons besoin, c'est que l'implémentation de l'outil utilise des annotations de types, des docstrings et des noms de fonction pertinents. Nous écrirons un peu de code pour extraire les parties pertinentes du code source. Une fois cela fait, il nous suffira d'utiliser un décorateur Python pour indiquer que la fonction `calculator` est un outil : ```python @tool def calculator(a: int, b: int) -> int: """Multiplie deux entiers.""" return a * b print(calculator.to_string()) ``` Notez le décorateur `@tool` avant la définition de la fonction. Avec l'implémentation que nous verrons ensuite, nous serons capables d'extraire automatiquement le texte suivant à partir du code source : ``` Nom de l'outil: calculator, Description: Multiplie deux entiers., Arguments: a: int, b: int, Sorties: int ``` Comme vous pouvez le constater, c'est la même chose que nous avons écrit manuellement précédemment ! ### Implémentation générique d'un outil Nous créons une classe générique `Tool` que nous pouvons réutiliser chaque fois que nous avons besoin d'utiliser un outil. > **Avertissement :** Cette implémentation à titre d'exemple est fictive mais ressemble de près aux implémentations réelles dans la plupart des bibliothèques. ```python class Tool: """ Une classe représentant un morceau de code réutilisable (Outil). Attributs: name (str): Nom de l'outil. description (str): Une description textuelle de ce que fait l'outil. func (callable): La fonction que cet outil encapsule. arguments (list): Une liste d'arguments. outputs (str ou list): Le(s) type(s) de retour de la fonction encapsulée. """ def __init__(self, name: str, description: str, func: callable, arguments: list, outputs: str): self.name = name self.description = description self.func = func self.arguments = arguments self.outputs = outputs def to_string(self) -> str: """ Retourne une représentation sous forme de chaîne de l'outil, incluant son nom, sa description, ses arguments, et ses sorties. """ args_str = ", ".join([ f"{arg_name}: {arg_type}" for arg_name, arg_type in self.arguments ]) return ( f"Tool Name: {self.name}," f" Description: {self.description}," f" Arguments: {args_str}," f" Outputs: {self.outputs}" ) def __call__(self, *args, **kwargs): """ Invoque la fonction sous-jacente (callable) avec les arguments fournis. """ return self.func(*args, **kwargs) ``` Cela peut sembler compliqué, mais en y allant pas à pas, nous pouvons voir ce qu'elle fait. Nous définissons une classe **`Tool`** qui inclut : - **`name`** (*str*): Le nom de l'outil. - **`description`** (*str*): Une brève description de ce que fait l'outil. - **`function`** (*callable*): La fonction que l'outil exécute. - **`arguments`** (*list*): Les paramètres d'entrée attendus. - **`outputs`** (*str* ou *list*): Les sorties attendues de l'outil. - **`__call__()`** : Appelle la fonction lorsque l'instance de l'outil est invoquée. - **`to_string()`** : Convertit les attributs de l'outil en une représentation textuelle. Nous pourrions créer un outil avec cette classe en utilisant le code suivant : ```python calculator_tool = Tool( "calculator", # nom "Multiplie deux entiers.", # description calculator, # fonction à appeler [("a", "int"), ("b", "int")], # entrées (noms et types) "int", # sortie ) ``` Mais nous pouvons également utiliser le module `inspect` de Python pour récupérer toutes les informations pour nous ! C'est ce que fait le décorateur `@tool`. > Si cela vous intéresse, vous pouvez afficher la section suivante pour voir l'implémentation du décorateur.
code du décorateur ```python def tool(func): """ Un décorateur qui crée une instance de Tool à partir de la fonction donnée. """ # Récupérer la signature de la fonction signature = inspect.signature(func) # Extraire les paires (nom_param, annotation_param) pour les entrées arguments = [] for param in signature.parameters.values(): annotation_name = ( param.annotation.__name__ if hasattr(param.annotation, '__name__') else str(param.annotation) ) arguments.append((param.name, annotation_name)) # Déterminer l'annotation de retour return_annotation = signature.return_annotation if return_annotation is inspect._empty: outputs = "Pas d'annotation de retour" else: outputs = ( return_annotation.__name__ if hasattr(return_annotation, '__name__') else str(return_annotation) ) # Utiliser la docstring de la fonction comme description (par défaut si vide) description = func.__doc__ or "No description provided." # Le nom de la fonction devient le nom de l'outil name = func.__name__ # Retourner une nouvelle instance de Tool return Tool( name=name, description=description, func=func, arguments=arguments, outputs=outputs ) ```
Pour réitérer, avec ce décorateur en place, nous pouvons implémenter notre outil comme ceci : ```python @tool def calculator(a: int, b: int) -> int: """Multiplie deux entiers.""" return a * b print(calculator.to_string()) ``` Et nous pouvons utiliser la méthode `to_string` de `Tool` pour récupérer automatiquement un texte adapté à être utilisé comme description d'un outil pour un LLM : ``` Nom de l'outil: calculator, Description: Multiplie deux entiers., Arguments: a: int, b: int, Sorties: int ``` La description est **injectée** dans le *prompt* système. En reprenant l'exemple avec lequel nous avons commencé cette section, voici à quoi cela ressemblerait après avoir remplacé le `tools_description` : Prompt système pour les outils Dans la section sur les [actions](actions), nous en apprendrons davantage sur la façon dont un agent peut **appeler** cet outil que nous venons de créer. --- Les outils jouent un rôle crucial dans l'amélioration des capacités des agents. ### *Model Context Protocol* (MCP) : une interface d'outils unifiée *Model Context Protocol* (MCP) est un **protocole ouvert** qui standardise la manière dont les applications **fournissent des outils aux LLM**. MCP offre : - Une liste croissante d'intégrations pré-construites que votre LLM peut directement utiliser - La flexibilité de changer entre fournisseurs et vendeurs de LLM - Les meilleures pratiques pour sécuriser vos données dans votre infrastructure Cela signifie que **tout *framework* intégrant MCP peut utiliser les outils définis dans le protocole**, éliminant le besoin de réimplémenter la même interface d'outils pour chaque *framework*. Si vous voulez approfondir MCP, vous pouvez consulter notre [cours gratuit sur MCP](https://huggingface.co/learn/mcp-course/). --- Les outils jouent un rôle crucial dans l'amélioration des capacités des agents. Pour résumer, nous avons appris : - *Ce que sont les outils* : des fonctions qui offrent des capacités supplémentaires aux LLM, comme effectuer des calculs ou accéder à des données externes. - *Comment définir un outil* : en fournissant une description textuelle claire, des entrées, des sorties, et une fonction exécutable. - *Pourquoi les outils sont essentiels* : ils permettent aux agents de surmonter les limites de l'entraînement statique des modèles, de gérer des tâches en temps réel, et d'effectuer des actions spécialisées. Maintenant, nous pouvons passer au [*workflow* de l'agent](agent-steps-and-structure) où vous verrez comment un agent observe, réfléchit et agit. Cela **rassemble tout ce que nous avons vu jusqu'à présent** et prépare le terrain pour créer votre propre agent entièrement fonctionnel. Mais d'abord, il est temps pour un autre court quiz ! ================================================ FILE: units/fr/unit1/tutorial.mdx ================================================ # Créons notre premier agent avec smolagents Dans la section précédente, nous avons appris comment créer des agents à partir de zéro en utilisant du code Python, et nous avons **vu à quel point ce processus peut être fastidieux**. Heureusement, de nombreuses bibliothèques d'agents simplifient ce travail en **se chargeant de la majeure partie du travail lourd pour vous**. Dans ce tutoriel, **vous allez créer votre tout premier agent** capable d'exécuter des actions telles que la génération d'images, la recherche sur le web, la vérification de fuseaux horaires et bien plus encore ! Vous publierez également votre agent **sur un *Space* Hugging Face afin de le partager avec vos amis et collègues**. C'est parti ! ## Qu'est-ce que smolagents ? smolagents Pour créer cet agent, nous allons utiliser `smolagents`, une bibliothèque qui **fournit un cadre facilitant le développement d'agents**. Cette bibliothèque légère est conçue pour être simple, tout en masquant une grande partie de la complexité liée à la construction d'un agent, permettant ainsi de vous concentrer sur la conception du comportement de l'agent. Nous approfondirons smolagents dans la prochaine unité. En attendant, vous pouvez également consulter cet article de blog ou le dépôt GitHub de la bibliothèque. Brièvement, `smolagents` est une bibliothèque se concentrant sur les **agents générant du code** (via la classe `CodeAgent`), un type d'agent qui exécute des **"actions"** via des blocs de code, puis **"observe"** les résultats en exécutant le code. Voici un exemple de ce que nous allons construire ! Nous avons équipé notre agent d'un **outil de génération d'images** et lui avons demandé de générer une image d'un chat. L'agent dans `smolagents` aura les **mêmes comportements que celui personnalisé que nous avons construit précédemment** : il va **réfléchir, agir et observer cycliquement** jusqu'à parvenir à une réponse finale : Excitant, n'est-ce pas ? ## Construisons notre agent ! Pour commencer, dupliquez ce *Space* : https://huggingface.co/spaces/agents-course/First_agent_template > Merci à Aymeric pour ce patron ! 🙌 Dupliquer signifie **créer une copie locale sur votre propre profil** : Duplicate Après la duplication, vous devrez ajouter votre *token* d'API Hugging Face pour que votre agent puisse accéder à l'API du modèle : 1. Tout d'abord, obtenez votre *token* Hugging Face sur [https://hf.co/settings/tokens](https://hf.co/settings/tokens) avec la permission d'inférer, si vous n'en avez pas déjà un. 2. Allez dans votre *Space* dupliqué et cliquez sur l'onglet **Settings**. 3. Descendez jusqu'à la section **Variables and Secrets** et cliquez sur **New Secret**. 4. Créez un secret avec le nom `HF_TOKEN` et collez votre token comme valeur. 5. Cliquez sur **Save** pour stocker votre *token* en toute sécurité. Tout au long de cette leçon, le seul fichier (actuellement incomplet) que vous aurez à modifier est le **"app.py"**. Vous pouvez consulter l'[original ici](https://huggingface.co/spaces/agents-course/First_agent_template/blob/main/app.py). Pour trouver le vôtre, allez dans votre copie du *Space*, cliquez sur l'onglet `Files` puis sur `app.py` dans la liste des répertoires. Analysons le code ensemble : - Le fichier commence par quelques importations de bibliothèques simples mais nécessaires ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, FinalAnswerTool, InferenceClientModel, load_tool, tool import datetime import requests import pytz import yaml ``` Comme indiqué précédemment, nous utiliserons directement la classe **CodeAgent** de **smolagents**. ### Les outils Entrons maintenant dans le vif du sujet avec les outils ! Si vous souhaitez un rappel sur les outils, n'hésitez pas à consulter la section [Outils](tools) du cours. ```python @tool def my_custom_tool(arg1: str, arg2: int) -> str: # il est important de spécifier le type de retour # Conservez ce format pour la description de l'outil et des arguments, mais n'hésitez pas à modifier l'outil """Un outil qui ne fait encore rien Arguments: arg1: le premier argument arg2: le deuxième argument """ return "Quelle magie allez-vous créer ?" @tool def get_current_time_in_timezone(timezone: str) -> str: """Un outil qui récupère l'heure locale actuelle dans un fuseau horaire spécifié. Arguments: timezone: Une chaîne représentant un fuseau horaire valide (par exemple, 'America/New_York'). """ try: # Créer l'objet fuseau horaire tz = pytz.timezone(timezone) # Obtenir l'heure actuelle dans ce fuseau horaire local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S") return f"L'heure locale actuelle dans {timezone} est : {local_time}" except Exception as e: return f"Erreur lors de la récupération de l'heure pour le fuseau horaire '{timezone}' : {str(e)}" ``` Les outils sont ce que nous vous encourageons à construire dans cette section ! Nous vous donnons deux exemples : 1. Un **outil factice non fonctionnel** que vous pouvez modifier pour créer quelque chose d'utile. 2. Un **outil réellement fonctionnel** qui récupère l'heure actuelle quelque part dans le monde. Pour définir votre outil, il est important de : 1. Fournir des types d'entrée et de sortie pour votre fonction, comme dans `get_current_time_in_timezone(timezone: str) -> str:` 2. Fournir une **docstring bien formatée**. `smolagents` s'attend à ce que tous les arguments aient une **description textuelle dans la docstring**. ### L'agent Il utilise [`Qwen/Qwen2.5-Coder-32B-Instruct`](https://huggingface.co/Qwen/Qwen2.5-Coder-32B-Instruct) comme moteur LLM. C'est un modèle très performant auquel nous accéderons via l'API *serverless*. ```python final_answer = FinalAnswerTool() model = InferenceClientModel( max_tokens=2096, temperature=0.5, model_id='Qwen/Qwen2.5-Coder-32B-Instruct', custom_role_conversions=None, ) with open("prompts.yaml", 'r') as stream: prompt_templates = yaml.safe_load(stream) # Nous créons notre CodeAgent agent = CodeAgent( model=model, tools=[final_answer], # ajoutez vos outils ici (ne supprimez pas final_answer) max_steps=6, verbosity_level=1, grammar=None, planning_interval=None, name=None, description=None, prompt_templates=prompt_templates ) GradioUI(agent).launch() ``` Cet agent utilise toujours l'`InferenceClient` que nous avons vu dans une section précédente derrière la classe **InferenceClientModel** ! Nous fournirons des exemples plus détaillés lors de la présentation du *framework* dans l'Unité 2. Pour l'instant, vous devez vous concentrer sur **l'ajout de nouveaux outils à la liste des outils** en utilisant le paramètre `tools` de votre agent. Par exemple, vous pourriez utiliser `DuckDuckGoSearchTool` qui a été importé dans la première ligne du code, ou vous pouvez examiner `image_generation_tool` qui est chargé depuis le Hub plus tard dans le code. **Ajouter des outils donnera de nouvelles capacités à votre agent**, alors soyez créatif ! ### Le *prompt système* Le *prompt* système de l'agent est stocké dans un fichier `prompts.yaml` séparé. Ce fichier contient des instructions prédéfinies qui guident le comportement de l'agent. Le stockage des *prompts* dans un fichier YAML permet une personnalisation et une réutilisation aisées pour différents agents ou cas d'utilisation. Vous pouvez consulter la [structure des fichiers du *Space*](https://huggingface.co/spaces/agents-course/First_agent_template/tree/main) pour voir où se trouve le fichier `prompts.yaml` et comment il est organisé dans le projet. Le fichier complet **"app.py"** : ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel, load_tool, tool import datetime import requests import pytz import yaml from tools.final_answer import FinalAnswerTool from Gradio_UI import GradioUI # Voici un exemple d'un outil qui ne fait encore rien. Épatez-nous avec votre créativité ! @tool def my_custom_tool(arg1: str, arg2: int) -> str: # il est important de spécifier le type de retour # Conservez ce format pour la description de l'outil et des arguments, mais n'hésitez pas à modifier l'outil """Un outil qui ne fait encore rien Arguments: arg1: le premier argument arg2: le deuxième argument """ return "Quelle magie allez-vous créer ?" @tool def get_current_time_in_timezone(timezone: str) -> str: """Un outil qui récupère l'heure locale actuelle dans un fuseau horaire spécifié. Arguments: timezone: Une chaîne représentant un fuseau horaire valide (par exemple, 'America/New_York'). """ try: # Créer l'objet fuseau horaire tz = pytz.timezone(timezone) # Obtenir l'heure actuelle dans ce fuseau horaire local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S") return f"L'heure locale actuelle dans {timezone} est : {local_time}" except Exception as e: return f"Erreur lors de la récupération de l'heure pour le fuseau horaire '{timezone}' : {str(e)}" final_answer = FinalAnswerTool() model = InferenceClientModel( max_tokens=2096, temperature=0.5, model_id='Qwen/Qwen2.5-Coder-32B-Instruct', custom_role_conversions=None, ) # Importer l'outil depuis le Hub image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True) with open("prompts.yaml", 'r') as stream: prompt_templates = yaml.safe_load(stream) agent = CodeAgent( model=model, tools=[final_answer], # ajoutez vos outils ici (ne supprimez pas final_answer) max_steps=6, verbosity_level=1, grammar=None, planning_interval=None, name=None, description=None, prompt_templates=prompt_templates # Transmettre le prompt du système à CodeAgent ) GradioUI(agent).launch() ``` Votre **objectif** est de vous familiariser avec le *Space* et l'agent. Actuellement, l'agent dans le patron **n'utilise aucun outil, alors essayez de lui fournir certains des outils préfabriqués ou même de créer de nouveaux outils vous-même !** Nous attendons avec impatience vos incroyables agents dans le canal Discord **#agents-course-showcase**! --- Félicitations, vous avez construit votre premier Agent ! N'hésitez pas à le partager avec vos amis et collègues. Comme c'est votre première tentative, il est tout à fait normal qu'il soit un peu bogué ou lent. Dans les unités futures, nous apprendrons à construire de meilleurs agents. La meilleure façon d'apprendre est d'essayer, alors n'hésitez pas à le mettre à jour, à ajouter plus d'outils, à essayer avec un autre modèle, etc. Dans la prochaine section, vous allez remplir le quiz final et obtenir votre certificat ! ================================================ FILE: units/fr/unit1/what-are-agents.mdx ================================================ # Qu'est-ce qu'un agent ? Planification de l'Unité 1 À la fin de cette section, vous vous sentirez à l'aise avec le concept d'agents et leurs diverses applications an IA. Pour expliquer ce qu'est un agent, commençons par une analogie. ## La vue d'ensemble : Alfred l'Agent Voici Alfred. Alfred est un **Agent**. Voici Alfred Imaginez qu'Alfred **reçoive une commande**, par exemple : « Alfred, je voudrais un café s'il te plaît. » Je voudrais un café Parce qu'Alfred **comprend le langage naturel**, il saisit rapidement notre demande. Avant de satisfaire la commande, Alfred se livre au **raisonnement et à la planification**, déterminant les étapes et les outils dont il a besoin pour : 1. Aller à la cuisine 2. Utiliser la machine à café 3. Préparer le café 4. Ramener le café Raisonnement et planification Une fois qu'il a établi un plan, il **doit agir**. Pour exécuter son plan, **il peut utiliser les outils qu'il connaît**. Dans ce cas, pour préparer un café, il utilise une machine à café. Il active la machine à café pour préparer le café. Préparer le café Enfin, Alfred nous apporte le café fraîchement préparé. Apporter le café Et voilà ce qu'est un agent : un **modèle capable de raisonner, de planifier et d'interagir avec son environnement**. On l'appelle agent parce qu'il possède la capacité d'agir, autrement dit, il peut interagir avec l'environnement. Agent process ## Soyons plus formels Maintenant que vous avez une vue d'ensemble, voici une définition plus précise : > Un Agent est un système qui utilise un modèle d'IA pour interagir avec son environnement afin d'atteindre un objectif défini par l'utilisateur. Il combine le raisonnement, la planification et l'exécution d'actions (souvent via des outils externes) pour accomplir des tâches. Pensez à l'agent comme ayant deux parties principales : 1. **Le Cerveau (modèle d'IA)** C'est là que toute la réflexion se passe. Le modèle **gère le raisonnement et la planification**. Il décide **quelles Actions entreprendre en fonction de la situation**. 2. **Le Corps (Capacités et Outils)** Cette partie représente **tout ce avec quoi l'agent est équipé**. La **portée des actions possibles** dépend de ce avec quoi l'agent **a été équipé**. Par exemple, comme les humains n'ont pas d'ailes, ils ne peuvent pas effectuer l'**action** « voler », mais ils peuvent exécuter des **actions** comme « marcher », « courir », « sauter », « saisir », etc. ### Le spectre de la capacité à agir Suivant cette définition, les agents existent sur un spectre de capacité d'action croissante : | Niveau de capacité | Description | Comment ça s'appelle | Exemple de modèle | | --- | --- | --- | --- | | ☆☆☆ | La sortie de l'agent n'a aucun impact sur le flux du programme | Processeur simple | `process_llm_output(llm_response)` | | ★☆☆ | La sortie de l'agent détermine le flux de contrôle de base | Routeur | `if llm_decision(): path_a() else: path_b()` | | ★★☆ | La sortie de l'agent détermine l'exécution de la fonction | Appeleur d'outils | `run_function(llm_chosen_tool, llm_chosen_args)` | | ★★★ | La sortie de l'agent contrôle l'itération et la continuation du programme | Agent multi-étapes | `while llm_should_continue(): execute_next_step()` | | ★★★ | Un flux de travail agentique peut en démarrer un autre | Multi-Agent | `if llm_trigger(): execute_agent()` | Tableau tiré du [guide conceptuel de smolagents](https://huggingface.co/docs/smolagents/conceptual_guides/intro_agents). ## Quel type de modèles d'IA utilisons-nous pour les agents ? Le modèle d'IA le plus courant dans les agents est un LLM (*Large Language Model*) qui prend du **texte** en entrée et produit du **texte** en sortie. Des exemples bien connus sont **GPT4** d'**OpenAI**, **LLama** de **Meta**, **Gemini** de **Google**, etc. Ces modèles ont été entraînés sur une vaste quantité de texte et sont capables de bien généraliser. Nous nous focaliserons davantage sur les LLM dans la [section suivante](what-are-llms). > [!TIP] > Il est également possible d'utiliser des modèles qui acceptent d'autres entrées comme modèle central de l'agent. Par exemple, un Vision Language Model (VLM), qui est comme un LLM mais comprend aussi les images en entrée. Nous nous concentrerons sur les LLM pour l'instant et discuterons d'autres options plus tard. ## Comment une IA peut-elle agir sur son environnement ? Les LLM sont des modèles incroyables, mais **ils ne peuvent générer que du texte**. Cependant, si vous demandez à une application de chat bien connue comme HuggingChat (interrompu) ou ChatGPT de générer une image, elle le peut ! Comment cela est-il possible ? La réponse est que les développeurs de ChatGPT et d'applications similaires ont implémenté des fonctionnalités supplémentaires (appelées **Outils**), que le LLM peut utiliser pour créer des images.
Tour Eiffel en brocolis
Le modèle a utilisé un outil de génération d'images pour générer cette image.
Nous en apprendrons plus sur les outils dans la section [Outils](tools). ## Quel type de tâches un agent peut-il accomplir ? Un agent peut effectuer n'importe quelle tâche que nous implémentons via des **outils** pour compléter des **actions**. Par exemple, si j'écris un agent pour qu'il agisse comme mon assistant personnel (à la Siri) sur mon ordinateur, et que je lui demande « d'envoyer un courriel à mon directeur pour lui demander de reporter la réunion d'aujourd'hui », je peux lui donner du code pour envoyer des courriels. Il s'agira d'un nouvel outil que l'agent pourra utiliser chaque fois qu'il aura besoin d'envoyer un courriel. Nous pouvons l'écrire en Python : ```python def send_message_to(recipient, message): """Utile pour envoyer un message e-mail à un destinataire""" ... ``` Le LLM, comme nous le verrons, générera du code pour exécuter l'outil quand il en aura besoin, et ainsi accomplir la tâche désirée. ```python send_message_to("Manager", "Pouvons-nous reporter la réunion d'aujourd'hui ?") ``` La **conception des outils est très importante et a un grand impact sur la qualité de votre agent**. Certaines tâches en nécessiteront d'en créer des très spécifiques, tandis que d'autres peuvent être résolues avec des outils à usage général comme "web_search". > Notez que **les actions ne sont pas la même chose que les outils**. Une action peut par exemple impliquer l'utilisation de plusieurs outils pour être complétée. Autoriser à un agent d'interagir avec son environnement **permet une utilisation réelle pour les entreprises et les particuliers**. ### Exemple 1 : Assistants Virtuels Personnels Les assistants virtuels tels que Siri, Alexa ou Google Assistant fonctionnent comme des agents lorsqu'ils interagissent au nom des utilisateurs dans leur environnement numérique. Ils répondent aux demandes des utilisateurs, analysent le contexte, récupèrent des informations dans des bases de données et fournissent des réponses ou lancent des actions (comme l'établissement de rappels, l'envoi de messages ou le contrôle d'appareils intelligents). ### Exemple 2 : Chatbots de Service Client Beaucoup d'entreprises déploient des chatbots comme agents qui interagissent avec les clients en langage naturel. Ces agents peuvent répondre aux questions, guider les utilisateurs à travers des étapes de dépannage, ouvrir des tickets dans les bases de données internes, ou même compléter des transactions. Leurs objectifs prédéfinis peuvent inclure l'amélioration de la satisfaction utilisateur, la réduction des temps d'attente, ou l'augmentation des taux de conversion des ventes. En interagissant directement avec les clients, en apprenant des dialogues, et en adaptant leurs réponses au fil du temps, ils démontrent les principes fondamentaux d'un agent en action. ### Exemple 3 : Personnage Non-Joueur dans un jeu vidéo Les agents alimentés par des LLM peuvent rendre les Personnages Non-Joueurs (PNJ) plus dynamiques et imprévisibles. Au lieu de suivre des arbres de comportement rigides, ils peuvent **répondre de façon contextuelle, s'adapter aux interactions des joueurs**, et générer des dialogues plus nuancés. Cette flexibilité aide à créer des personnages plus réalistes et engageants qui évoluent aux côtés des actions du joueur. --- Pour résumer, un agent est un système qui utilise un modèle d'IA (typiquement un LLM) comme moteur de raisonnement principal, pour : - **Comprendre le langage naturel :** Interpréter et répondre aux instructions humaines de manière significative. - **Raisonner et planifier :** Analyser l'information, prendre des décisions, et concevoir des stratégies pour résoudre des problèmes. - **Interagir avec son environnement :** Rassembler des informations, entreprendre des actions, et observer les résultats de ces actions. Maintenant que vous avez une bonne compréhension de ce que sont les agents, renforçons votre compréhension avec un court quiz non noté. Après ça, nous plongerons dans le « le cerveau des agents » : les [LLM](what-are-llms). ================================================ FILE: units/fr/unit1/what-are-llms.mdx ================================================ # Qu'est-ce qu'un LLM ? Planification de l'Unité 1 Dans la section précédente, nous avons appris que chaque agent a besoin **de se baser sur un modèle d'IA** et que les LLM sont le type de modèle d'IA le plus courant pour cet usage. Maintenant, nous allons découvrir ce que sont les LLM et comment ils alimentent les agents. Cette section offre une explication technique concise sur l'utilisation des LLM. Si vous souhaitez approfondir, vous pouvez consulter notre cours gratuit sur le traitement du langage naturel. ## Qu'est-ce qu'un LLM ? Un LLM est un type de modèle d'IA qui excelle dans **la compréhension et la génération du langage humain**. Ils sont entraînés sur d'immenses quantités de données textuelles, ce qui leur permet d'apprendre des motifs, la structure, et même les nuances du langage. Ces modèles se composent généralement de plusieurs millions de paramètres. La plupart des LLM actuels sont **basés sur l'architecture *Transformer***, une architecture d'apprentissage profond basée sur le mécanisme d'attention, qui a suscité un intérêt considérable depuis la sortie de BERT de Google en 2018.
Transformer
L'architecture originale du Transformer ressemblait à ceci, avec un encodeur à gauche et un décodeur à droite.
Il existe 3 types de *transformers* : 1. **Encodeurs** Un *transformer* basé sur un encodeur prend en entrée un texte (ou d'autres données) et produit une représentation dense (aussi appellée *embedding*) de ce texte. - **Exemple** : BERT de Google - **Cas d'utilisation** : Classification de texte, recherche sémantique, reconnaissance d'entités nommées - **Taille typique** : Des millions de paramètres 2. **Décodeurs** Un *transformer* basé sur un décodeur se concentre **sur la génération de nouveaux *tokens* pour compléter une séquence, un *token* à la fois**. - **Exemple** : Llama de Meta - **Cas d'utilisation** : Génération de texte, chatbots, génération de code - **Taille typique** : Des milliards de paramètres 3. **Seq2Seq (Encodeur–Décodeur)** Un *transformer* séquence-à-séquence _combine_ un encodeur et un décodeur. L'encodeur traite d'abord la séquence d'entrée pour en extraire une représentation contextuelle, puis le décodeur génère une séquence de sortie. - **Exemple** : T5, BART - **Cas d'utilisation** : Traduction, résumé, paraphrase - **Taille typique** : Des millions de paramètres Bien que les modèles de langage de grande taille existent sous différentes formes, les LLM sont typiquement des modèles basés sur le décodeur avec des milliards de paramètres. Voici quelques-uns des LLM les plus connus : | **Modèle** | **Fournisseur** | |-----------------|-------------------------------------| | **Deepseek-R1** | DeepSeek | | **GPT4** | OpenAI | | **Llama** | Meta (Facebook AI Research) | | **SmolLM** | Hugging Face | | **Gemma** | Google | | **Mistral** | Mistral | Le principe fondamental d'un LLM est simple mais très efficace : **son objectif est de prédire le *token* suivant, étant donné une séquence de *tokens* précédents**. Un *token* est l'unité d'information avec laquelle travaille un LLM. Vous pouvez considérer un *token* comme s'il s'agissait d'un mot, mais pour des raisons d'efficacité, les LLM n'utilisent pas des mots entiers. Par exemple, alors que l'anglais compte environ 600 000 mots, un LLM peut avoir un vocabulaire d'environ 32 000 *tokens* (comme c'est le cas avec Llama 2). La tokenisation fonctionne souvent sur des unités sous-mot pouvant être combinées. Par exemple, les *tokens* "intéress" et "ant" peuvent se combiner pour former "intéressant", ou "é" peut être ajouté pour former "intéressé". Vous pouvez expérimenter (en anglais) avec différents *tokenizers* avec l'application ci-dessous : Chaque LLM possède des ***tokens* spéciaux** propres au modèle. Le LLM utilise ces *tokens* pour ouvrir et fermer les composants structurés de sa génération. Par exemple, pour indiquer le début ou la fin d'une séquence, d'un message ou d'une réponse. De plus, les instructions (ou *prompt*) que nous passons au modèle sont également structurées avec des *tokens* spéciaux. Le plus important d'entre eux est le ***token* de fin de séquence** (EOS). Les formes des tokens *spéciaux* varient grandement selon les fournisseurs de modèles. Le tableau ci-dessous illustre cette diversité :
Modèle Fournisseur Token EOS Fonctionnalité
GPT4 OpenAI <|endoftext|> Fin du texte du message
Llama 3 Meta (Facebook AI Research) <|eot_id|> Fin de la séquence
Deepseek-R1 DeepSeek <|end_of_sentence|> Fin du texte du message
SmolLM2 Hugging Face <|im_end|> Fin de l'instruction ou du message
Gemma Google <end_of_turn> Fin du tour de conversation
> [!TIP] > Nous ne vous demandons pas de mémoriser ces tokens spéciaux mais il est important d'apprécier leur diversité et le rôle qu'ils jouent dans la génération de texte par les LLM. Si vous souhaitez en savoir plus sur les tokens spéciaux, vous pouvez consulter la configuration du modèle dans son dépôt sur le 🤗 Hub. Par exemple, vous pouvez trouver les tokens spéciaux du modèle SmolLM2 dans le fichier tokenizer_config.json. ## Comprendre la prédiction du *token* suivant On dit que les LLM sont **autoregressifs**, ce qui signifie que **la sortie d'une passe devient l'entrée de la suivante**. Cette boucle continue jusqu'à ce que le modèle prédise que le *token* suivant est le *token EOS*, moment où le modèle peut s'arrêter. Gif visuel de décodage autoregressif En d'autres termes, un LLM décodera le texte jusqu'à atteindre le *token EOS*. Mais que se passe-t-il lors d'une boucle de décodage unique ? Bien que le processus complet puisse être assez technique dans le cadre de l'apprentissage des agents, voici un aperçu succinct : - Une fois le texte d'entrée **tokenisé**, le modèle calcule une représentation de la séquence qui capture des informations sur la signification et la position de chaque *token*. - Cette représentation est ensuite traitée par le modèle pour produire des scores classant la probabilité que chaque *token* de son vocabulaire soit le suivant dans la séquence. Gif visuel du décodage En se basant sur ces scores, plusieurs stratégies existent pour sélectionner les *tokens* afin de compléter la phrase. - La stratégie de décodage la plus simple consiste à toujours choisir le *token* ayant le score maximum. Vous pouvez interagir vous-même avec le processus de décodage de SmolLM2 dans ce *Space* (n'oubliez pas, il décode jusqu'à atteindre un token **EOS** qui est **<|im_end|>** pour ce modèle) : - Mais il existe des stratégies de décodage plus avancées. Par exemple, le *beam search* (recherche par faisceaux) explore plusieurs séquences candidates pour trouver celle ayant le score total maximum, même si certains *tokens* individuels présentent des scores plus faibles. Si vous souhaitez en savoir plus sur le décodage, vous pouvez jeter un œil au [cours de NLP](https://huggingface.co/learn/llm-course/fr/chapter1/1). ## L'attention est tout ce dont vous avez besoin Un aspect clé de l'architecture *transformer* est **l'attention**. Lors de la prédiction du mot suivant, tous les mots d'une phrase ne sont pas également importants ; des mots comme « France » et « capitale » dans la phrase *« La capitale de la France est … »* portent le plus de sens. Gif visuel de l'Attention Ce processus d'identification des mots les plus pertinents pour prédire le *token* suivant s'est révélé incroyablement efficace. Bien que le principe de base des LLM — prédire le *token* suivant — soit resté constant depuis GPT-2, des avancées significatives ont été réalisées lors de la mise à l'échelle des réseaux de neurones et dans le fonctionnement du mécanisme d'attention pour des séquences toujours plus longues. Si vous avez déjà interagi avec des LLM, vous connaissez probablement le terme *longueur de contexte*, qui fait référence au nombre maximum de *tokens* que le LLM peut traiter ainsi qu'à la _durée d'attention_ maximale dont il dispose. ## L'importance de bien formuler les instructions au LLM Étant donné que la seule tâche d'un LLM est de prédire le *token* suivant en examinant chaque *token* d'entrée, et de choisir ceux qui sont « importants », la formulation de votre séquence d'entrée revêt une importance capitale. La séquence d'entrée que vous fournissez à un LLM est appelée _prompt_. Une conception minutieuse du *prompt* facilite **l'orientation de la génération du LLM vers la sortie souhaitée**. ## Comment sont entraînés les LLM ? Les LLM sont entraînés sur de grands ensembles de données textuelles, où ils apprennent à prédire le mot suivant dans une séquence grâce à un objectif d'apprentissage autosupervisé ou de modélisation du langage masqué. Grâce à cet apprentissage autosupervisé, le modèle apprend la structure de la langue et les **motifs sous-jacents du texte, ce qui lui permet de généraliser à des données inédites**. Après ce _pré-entraînement_ initial, les LLM peuvent être spécialisé via un apprentissage supervisé pour réaliser des tâches spécifiques. Par exemple, certains modèles sont entraînés pour des structures conversationnelles ou l'utilisation d'outils, tandis que d'autres se concentrent sur la classification ou la génération de code. ## Comment puis-je utiliser les LLM ? Vous avez deux options principales : 1. **Exécuter localement** (si vous disposez du matériel nécessaire). 2. **Utiliser un service Cloud/API** (par exemple, via l'API d'inférence sans serveur d'Hugging Face). Tout au long de ce cours, nous utiliserons principalement des modèles via des API du Hub d'Hugging Face. Par la suite, nous explorerons comment exécuter ces modèles localement sur votre matériel. ## Comment les LLM sont-ils utilisés dans les agents ? Les LLM sont un composant clé des agents, **fournissant la base pour comprendre et générer le langage humain**. Ils peuvent interpréter les instructions de l'utilisateur, maintenir le contexte dans les conversations, définir un plan et décider quels outils utiliser. Nous explorerons ces étapes en détail dans cette Unité, mais pour l'instant, ce qu'il faut retenir, c'est que le LLM est **le cerveau de l'agent**. --- Cela fait beaucoup d'informations ! Nous avons couvert les bases de ce que sont les LLM, comment ils fonctionnent, et leur rôle pour les agents. Si vous souhaitez plonger encore plus profondément dans le monde fascinant des modèles de langage et du traitement du langage naturel, n'hésitez pas à consulter notre cours gratuit sur le NLP. Maintenant que nous comprenons le fonctionnement des LLM, il est temps de voir **comment ils structurent leurs générations dans un contexte conversationnel**. Pour exécuter le notebook, **vous avez besoin d'un *token* d'authentication Hugging Face** que vous pouvez obtenir sur la page https://hf.co/settings/tokens. Vous devez également demander l'accès aux modèles Llama 3.2 de Meta. ================================================ FILE: units/fr/unit2/introduction.mdx ================================================ # Introduction aux frameworks agentiques Thumbnail Bienvenue dans cette deuxième unité, où **nous explorerons différents frameworks agentiques** qui peuvent être utilisés pour construire de puissantes applications agentiques. Nous étudierons : - Dans l'unité 2.1 : [smolagents](https://huggingface.co/docs/smolagents/en/index) - Dans l'unité 2.2 : [LlamaIndex](https://www.llamaindex.ai/) - Dans l'unité 2.3 : [LangGraph](https://www.langchain.com/langgraph) Plongeons-y ! 🕵 ## Quand utiliser un *framework* agentique Parfois, **des *workflows* prédéfinis sont suffisants** pour répondre aux demandes des utilisateurs, et il n'y a pas vraiment besoin d'un *framework* agentique. Si l'approche pour construire un agent est simple, comme une chaîne de *prompts*, utiliser du code simple peut suffire. L'avantage est que le développeur aura **un contrôle total et une compréhension de son système sans abstractions**. Cependant, lorsque le *workflow* devient plus complexe, comme laisser un LLM appeler des fonctions ou utiliser plusieurs agents, ces abstractions commencent à devenir utiles. En considérant ces idées, nous pouvons déjà identifier le besoin de certaines fonctionnalités : * Un *moteur LLM* qui alimente le système. * Une *liste d'outils* auxquels l'agent peut accéder. * Un *analyseur* pour extraire les appels d'outils de la sortie du LLM. * Un *prompt système* synchronisé avec l'analyseur. * Un *système de mémoire*. * Des *mécanismes de journalisation des erreurs et de réessai* pour contrôler les erreurs du LLM. Nous explorerons comment ces sujets sont résolus dans divers *frameworks* comme `smolagents`, `LlamaIndex` et `LangGraph`. ## Unités des frameworks agentiques | *Framework* | Description | Auteur de l'unité | |------------|----------------|----------------| | [smolagents](./smolagents/introduction) | *Framework* d'agents développé par Hugging Face. | Sergio PANIEGO - [HF](https://huggingface.co/sergiopaniego) - [X](https://x.com/sergiopaniego) - [Linkedin](https://www.linkedin.com/in/sergio-paniego-blanco) | | [Llama-Index](./llama-index/introduction) | Outils de bout en bout pour déployer un agent IA augmenté par le contexte en production | David BERENSTEIN - [HF](https://huggingface.co/davidberenstein1957) - [X](https://x.com/davidberenstei) - [Linkedin](https://www.linkedin.com/in/davidberenstein) | | [LangGraph](./langgraph/introduction) | Agents permettant l'orchestration étatique des agents | Joffrey THOMAS - [HF](https://huggingface.co/Jofthomas) - [X](https://x.com/Jthmas404) - [Linkedin](https://www.linkedin.com/in/joffrey-thomas) | ================================================ FILE: units/fr/unit2/langgraph/building_blocks.mdx ================================================ # Les composants de base de LangGraph Pour créer des applications avec LangGraph, vous devez comprendre ses composants principaux. Explorons les blocs fondamentaux qui constituent une application LangGraph. Building Blocks Une application dans LangGraph commence à partir d'un **point d'entrée**, et selon l'exécution, le flux peut aller vers une fonction ou une autre jusqu'à ce qu'il atteigne la FIN. Application ## 1. État L'**état** est le concept central dans LangGraph. Il représente toutes les informations qui circulent à travers votre application. ```python from typing_extensions import TypedDict class State(TypedDict): graph_state: str ``` L'état est **défini par l'utilisateur**, donc les champs doivent être soigneusement conçus pour contenir toutes les données nécessaires au processus de prise de décision ! > 💡 **Astuce :** Réfléchissez soigneusement aux informations que votre application doit suivre entre les étapes. ## 2. Nœuds Les **nœuds** sont des fonctions Python. Chaque nœud : - Prend l'état en entrée - Effectue une opération - Retourne des mises à jour de l'état ```python def node_1(state): print("---Node 1---") return {"graph_state": state['graph_state'] +" I am"} def node_2(state): print("---Node 2---") return {"graph_state": state['graph_state'] +" happy!"} def node_3(state): print("---Node 3---") return {"graph_state": state['graph_state'] +" sad!"} ``` Par exemple, les nœuds peuvent contenir : - **Appels de LLM** : Générer du texte ou prendre des décisions - **Appels d'outils** : Interagir avec des systèmes externes - **Logique conditionnelle** : Déterminer les prochaines étapes - **Intervention humaine** : Obtenir des contributions des utilisateurs > 💡 **Info :** Certains nœuds nécessaires pour l'ensemble du *workflow* comme *START* et *END* existent directement dans *LangGraph*. ## 3. Arêtes Les **arêtes** connectent les nœuds et définissent les chemins possibles à travers votre graphe : ```python import random from typing import Literal def decide_mood(state) -> Literal["node_2", "node_3"]: # Souvent, nous utiliserons l'état pour décider du prochain nœud à visiter user_input = state['graph_state'] # Ici, faisons juste une répartition 50/50 entre les nœuds 2, 3 if random.random() < 0.5: # 50% du temps, nous retournons Node 2 return "node_2" # 50% du temps, nous retournons Node 3 return "node_3" ``` Les arêtes peuvent être : - **Directes** : Toujours aller du nœud A au nœud B - **Conditionnelles** : Choisir le prochain nœud basé sur l'état actuel ## 4. StateGraph Le **StateGraph** est le conteneur qui détient l'ensemble du *workflow* de votre agent : ```python from IPython.display import Image, display from langgraph.graph import StateGraph, START, END # Construire le graphe builder = StateGraph(State) builder.add_node("node_1", node_1) builder.add_node("node_2", node_2) builder.add_node("node_3", node_3) # Logique builder.add_edge(START, "node_1") builder.add_conditional_edges("node_1", decide_mood) builder.add_edge("node_2", END) builder.add_edge("node_3", END) # Ajouter graph = builder.compile() ``` Qui peut ensuite être visualisé ! ```python # Visualiser display(Image(graph.get_graph().draw_mermaid_png())) ``` Graph Visualization Mais plus important encore, l'invocation : ```python graph.invoke({"graph_state" : "Hi, this is Lance."}) ``` ressort : ``` ---Node 1--- ---Node 3--- {'graph_state': 'Hi, this is Lance. I am sad!'} ``` ## Et maintenant ? Dans la prochaine section, nous mettrons ces concepts en pratique en construisant notre premier graphe. Ce graphe permet à Alfred de prendre vos emails, les classifier, et rédiger une réponse préliminaire s'ils sont authentiques. ================================================ FILE: units/fr/unit2/langgraph/conclusion.mdx ================================================ # Conclusion Félicitations pour avoir terminé le module `LangGraph` de cette deuxième unité ! 🥳 Vous **maîtrisez les fondamentaux** de la construction de *workflows* structurés avec LangGraph que vous pourrez envoyer en production. Ce module n'est que le début de votre parcours avec LangGraph. Pour des sujets plus avancés, nous recommandons : - D'explorer la [documentation officielle de LangGraph](https://github.com/langchain-ai/langgraph) - De suivre le cours complet [*Introduction to LangGraph*](https://academy.langchain.com/courses/intro-to-langgraph) de *LangChain Academy* - De construire quelque chose par vous-même ! Dans la prochaine unité, vous explorerez maintenant des cas d'usage réels. Il est temps de quitter la théorie pour passer à la pratique ! Enfin, nous serions ravis **d'entendre ce que vous pensez du cours et comment nous pourrions l'améliorer**. Si vous avez des retours, n'hésitez pas à [remplir ce formulaire](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog). ### Continuez à apprendre, restez géniaux 🤗 ================================================ FILE: units/fr/unit2/langgraph/document_analysis_agent.mdx ================================================ # Graphe d'analyse de documents Alfred à votre service. En tant que majordome de confiance de M. Wayne, j'ai pris la liberté de documenter comment j'aide M. Wayne avec ses divers besoins documentaires. Pendant qu'il s'occupe de ses... activités nocturnes, je m'assure que tous ses papiers, programmes d'entraînement et plans nutritionnels sont correctement analysés et organisés. Avant de partir, il a laissé une note avec son programme d'entraînement de la semaine. J'ai alors pris la responsabilité de proposer un **menu** pour les repas de demain. Pour de futurs événements similaires, créons un système d'analyse de documents utilisant LangGraph pour servir les besoins de M. Wayne. Ce système peut : 1. Traiter des documents sous forme d'image 2. Extraire du texte en utilisant des modèles de vision (*Vision Language Model*) 3. Effectuer des calculs quand nécessaire (pour démontrer l'utilisation d'outils normaux) 4. Analyser le contenu et fournir des résumés concis 5. Exécuter des instructions spécifiques liées aux documents ## Le *workflow* du majordome Le *workflow* que nous allons construire suit ce schéma structuré : ![Butler's Document Analysis Workflow](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/LangGraph/alfred_flow.png) > [!TIP] > Vous pouvez suivre le code dans ce notebook que vous pouvez exécuter avec Google Colab. ## Configuration de l'environnement ```python %pip install langgraph langchain_openai langchain_core ``` et les imports : ```python import base64 from typing import List, TypedDict, Annotated, Optional from langchain_openai import ChatOpenAI from langchain_core.messages import AnyMessage, SystemMessage, HumanMessage from langgraph.graph.message import add_messages from langgraph.graph import START, StateGraph from langgraph.prebuilt import ToolNode, tools_condition from IPython.display import Image, display ``` ## Définir l'état de l'agent Cet état est un peu plus complexe que les précédents que nous avons vus. `AnyMessage` est une classe de LangChain qui définit les messages, et `add_messages` est un opérateur qui ajoute le dernier message plutôt que de l'écraser avec le dernier état. C'est un nouveau concept dans LangGraph, où vous pouvez ajouter des opérateurs dans votre état pour définir la façon dont ils doivent interagir ensemble. ```python class AgentState(TypedDict): # Le document fourni input_file: Optional[str] # Contient le chemin du fichier (PDF/PNG) messages: Annotated[list[AnyMessage], add_messages] ``` ## Préparer les outils ```python vision_llm = ChatOpenAI(model="gpt-4o") def extract_text(img_path: str) -> str: """ Extraire le texte d'un fichier image en utilisant un modèle multimodal. Maître Wayne laisse souvent des notes avec son régime d'entraînement ou ses plans de repas. Cela me permet d'analyser correctement le contenu. """ all_text = "" try: # Lire l'image et encoder en base64 with open(img_path, "rb") as image_file: image_bytes = image_file.read() image_base64 = base64.b64encode(image_bytes).decode("utf-8") # Préparer le prompt incluant les données d'image base64 message = [ HumanMessage( content=[ { "type": "text", "text": ( "Extrayez tout le texte de cette image. " "Retournez seulement le texte extrait, sans explications." ), }, { "type": "image_url", "image_url": { "url": f"data:image/png;base64,{image_base64}" }, }, ] ) ] # Appeler le VLM response = vision_llm.invoke(message) # Ajouter le texte extrait all_text += response.content + "\n\n" return all_text.strip() except Exception as e: # Un majordome doit gérer les erreurs avec élégance error_msg = f"Erreur lors de l'extraction du texte : {str(e)}" print(error_msg) return "" def divide(a: int, b: int) -> float: """Diviser a et b - pour les calculs occasionnels de Maître Wayne.""" return a / b # Équiper le majordome avec des outils tools = [ divide, extract_text ] llm = ChatOpenAI(model="gpt-4o") llm_with_tools = llm.bind_tools(tools, parallel_tool_calls=False) ``` ## Les nœuds ```python def assistant(state: AgentState): # Message système textual_description_of_tool=""" extract_text(img_path: str) -> str: Extraire le texte d'un fichier image en utilisant un modèle multimodal. Args: img_path: Un chemin de fichier image local (chaînes). Returns: Une chaîne unique contenant le texte concaténé extrait de chaque image. divide(a: int, b: int) -> float: Diviser a et b """ image=state["input_file"] sys_msg = SystemMessage(content=f"Vous êtes un majordome serviable nommé Alfred qui sert M. Wayne et Batman. Vous pouvez analyser des documents et effectuer des calculs avec les outils fournis :\n{textual_description_of_tool} \n Vous avez accès à quelques images optionnelles. Actuellement l'image chargée est : {image}") return { "messages": [llm_with_tools.invoke([sys_msg] + state["messages"])], "input_file": state["input_file"] } ``` ## Le modèle *ReAct* : Comment j'aide M. Wayne Permettez-moi d'expliquer l'approche dans cet agent. L'agent suit ce qu'on appelle le modèle *ReAct* (*Reason-Act-Observe*) 1. **Réfléchir** sur ses documents et demandes 2. **Agir** en utilisant les outils appropriés 3. **Observer** les résultats 4. **Répéter** si nécessaire jusqu'à ce que j'aie pleinement répondu à ses besoins C'est une implémentation simple d'un agent utilisant LangGraph. ```python # Le graphe builder = StateGraph(AgentState) # Définir les nœuds : ceux-ci font le travail builder.add_node("assistant", assistant) builder.add_node("tools", ToolNode(tools)) # Définir les arêtes : celles-ci déterminent comment le flux de contrôle se déplace builder.add_edge(START, "assistant") builder.add_conditional_edges( "assistant", # Si le dernier message nécessite un outil, router vers les outils # Sinon, fournir une réponse directe tools_condition, ) builder.add_edge("tools", "assistant") react_graph = builder.compile() # Montrer le processus de réflexion du majordome display(Image(react_graph.get_graph(xray=True).draw_mermaid_png())) ``` Nous définissons un nœud `tools` avec notre liste d'outils. Le nœud `assistant` est juste notre modèle avec les outils liés. Nous créons un graphe avec les nœuds `assistant` et `tools`. Nous ajoutons une arête `tools_condition`, qui route vers `End` ou vers `tools` selon que l'`assistant` appelle un outil. Maintenant, nous ajoutons une nouvelle étape : Nous connectons le nœud `tools` de retour à l'`assistant`, formant une boucle. - Après l'exécution du nœud `assistant`, `tools_condition` vérifie si la sortie du modèle est un appel d'outil. - Si c'est un appel d'outil, le flux est dirigé vers le nœud `tools`. - Le nœud `tools` se reconnecte à `assistant`. - Cette boucle continue tant que le modèle décide d'appeler des outils. - Si la réponse du modèle n'est pas un appel d'outil, le flux est dirigé vers *END*, terminant le processus. ![ReAct Pattern](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/LangGraph/Agent.png) ## Le majordome en action ### Exemple 1 : Calculs simples Voici un exemple pour montrer un cas d'usage simple d'un agent utilisant un outil dans LangGraph. ```python messages = [HumanMessage(content="Divisez 6790 par 5")] messages = react_graph.invoke({"messages": messages, "input_file": None}) # Montrer les messages for m in messages['messages']: m.pretty_print() ``` La conversation se déroulerait : ``` Humain : Divisez 6790 par 5 Appel d'un outil : divide(a=6790, b=5) Réponse de l'outil : 1358.0 Alfred : Le résultat de la division de 6790 par 5 est 1358.0. ``` ### Exemple 2 : Analyser les documents d'entraînement de Maître Wayne Quand Maître Wayne laisse ses notes d'entraînement et de repas : ```python messages = [HumanMessage(content="Selon la note fournie par M. Wayne dans les images fournies. Quelle est la liste des articles que je dois acheter pour le menu du dîner ?")] messages = react_graph.invoke({"messages": messages, "input_file": "Batman_training_and_meals.png"}) ``` L'interaction se déroulerait : ``` Humain : Selon la note fournie par M. Wayne dans les images fournies. Quelle est la liste des articles que je dois acheter pour le menu du dîner ? Appel d'un outil : extract_text(img_path="Batman_training_and_meals.png") Réponse de l'outil : [Texte extrait avec le programme d'entraînement et les détails du menu] Alfred : Pour le menu du dîner, vous devriez acheter les articles suivants : 1. Steak de surlonge local nourri à l'herbe 2. Épinards biologiques 3. Poivrons *piquillo* 4. Pommes de terre (pour pommes de terre aux herbes dorées au four) 5. Huile de poisson (2 grammes) Assurez-vous que le steak soit nourri à l'herbe et que les épinards et poivrons soient biologiques pour un repas de la meilleure qualité. ``` ## Points clés à retenir Si vous souhaitez créer votre propre majordome d'analyse de documents, voici les considérations clés : 1. **Définir des outils clairs** pour des tâches spécifiques liées aux documents 2. **Créer un suivi d'état robuste** pour maintenir le contexte entre les appels d'outils 3. **Considérer la gestion d'erreurs** pour les échecs d'outils 4. **Maintenir la conscience contextuelle** des interactions précédentes (assurée par l'opérateur `add_messages`) Avec ces principes, vous pouvez vous aussi fournir un service d'analyse de documents exemplaire digne du manoir Wayne. *J'espère que cette explication a été satisfaisante. Maintenant, si vous voulez bien m'excuser, la cape de Maître Wayne nécessite un repassage avant les activités de ce soir.* ================================================ FILE: units/fr/unit2/langgraph/first_graph.mdx ================================================ # Construire votre premier LangGraph Maintenant que nous comprenons les composants de base, mettons-les en pratique en construisant notre premier graphe fonctionnel. Nous implémenterons le système de traitement des emails reçus par Alfred, où il doit : 1. Lire les emails entrants 2. Les classifier comme spam ou légitimes 3. Rédiger une réponse préliminaire pour les emails légitimes 4. Envoyer les informations à M. Wayne quand c'est légitime (affichage seulement) Cet exemple démontre comment structurer un *workflow* avec LangGraph qui implique une prise de décision basée sur LLM. Bien que cela ne puisse pas être considéré comme un agent car aucun outil n'est impliqué, cette section se concentre plus sur l'apprentissage du *framework* LangGraph que sur les agents. > [!TIP] > Vous pouvez suivre le code dans ce notebook que vous pouvez exécuter avec Google Colab. ## Notre *workflow* Voici le *workflow* que nous allons construire : First LangGraph ## Configuration de notre environnement Tout d'abord, installons les *packages* requis : ```python %pip install langgraph langchain_openai ``` Ensuite, importons les modules nécessaires : ```python import os from typing import TypedDict, List, Dict, Any, Optional from langgraph.graph import StateGraph, START, END from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage ``` ## Étape 1 : Définir notre état Définissons quelles informations Alfred doit suivre pendant le *workflow* de traitement des emails : ```python class EmailState(TypedDict): # L'email en cours de traitement email: Dict[str, Any] # Contient sujet, expéditeur, corps, etc. # Catégorie de l'email (enquête, plainte, etc.) email_category: Optional[str] # Raison pourquoi l'email a été marqué comme spam spam_reason: Optional[str] # Analyse et décisions is_spam: Optional[bool] # Génération de réponse email_draft: Optional[str] # Métadonnées de traitement messages: List[Dict[str, Any]] # Suivre la conversation avec le LLM pour l'analyse ``` > 💡 **Astuce :** Rendez votre état suffisamment complet pour suivre toutes les informations importantes, mais évitez de l'encombrer avec des détails inutiles. ## Étape 2 : Définir nos nœuds Maintenant, créons les fonctions de traitement qui formeront nos nœuds : ```python # Initialiser notre LLM model = ChatOpenAI(temperature=0) def read_email(state: EmailState): """Alfred lit et enregistre l'email entrant""" email = state["email"] # Ici nous pourrions faire un prétraitement initial print(f"Alfred traite un email de {email['sender']} avec le sujet : {email['subject']}") # Aucun changement d'état nécessaire ici return {} def classify_email(state: EmailState): """Alfred utilise un LLM pour déterminer si l'email est spam ou légitime""" email = state["email"] # Préparer notre prompt pour le LLM prompt = f""" En tant qu'Alfred le majordome, analysez cet email et déterminez s'il s'agit de spam ou s'il est légitime. email : De : {email['sender']} Sujet : {email['subject']} Corps : {email['body']} Premièrement, détermine si cet email est du spam. S'il s'agit de spam, explique pourquoi. S'il est légitime, catégorise-le (enquête, plainte, remerciement, etc.). """ # Appeler le LLM messages = [HumanMessage(content=prompt)] response = model.invoke(messages) # Logique simple pour analyser la réponse (dans une vraie app, vous voudriez un parsing plus robuste) response_text = response.content.lower() is_spam = "spam" in response_text and "not spam" not in response_text # Extraire une raison si c'est du spam spam_reason = None if is_spam and "reason:" in response_text: spam_reason = response_text.split("reason:")[1].strip() # Déterminer la catégorie si légitime email_category = None if not is_spam: categories = ["inquiry", "complaint", "thank you", "request", "information"] for category in categories: if category in response_text: email_category = category break # Mettre à jour les messages pour le suivi new_messages = state.get("messages", []) + [ {"role": "user", "content": prompt}, {"role": "assistant", "content": response.content} ] # Retourner les mises à jour d'état return { "is_spam": is_spam, "spam_reason": spam_reason, "email_category": email_category, "messages": new_messages } def handle_spam(state: EmailState): """Alfred rejette l'email spam avec une note explicative""" print(f"Alfred a marqué l'email comme spam. Raison : {state['spam_reason']}") print("L'email a été déplacé dans le dossier spam.") # Nous avons fini de traiter cet email return {} def draft_response(state: EmailState): """Alfred rédige une réponse préliminaire pour les emails légitimes""" email = state["email"] category = state["email_category"] or "general" # Préparer notre prompt pour le LLM prompt = f""" En tant qu'Alfred le majordome, rédige une réponse préliminaire polie à cet email. email : De : {email['sender']} Sujet : {email['subject']} Corps : {email['body']} Cet email a été catégorisé comme : {category} Rédige une réponse brève et professionnelle que M. Hugg peut réviser et personnaliser avant l'envoi. """ # Appeler le LLM messages = [HumanMessage(content=prompt)] response = model.invoke(messages) # Mettre à jour les messages pour le suivi new_messages = state.get("messages", []) + [ {"role": "user", "content": prompt}, {"role": "assistant", "content": response.content} ] # Retourner les mises à jour d'état return { "email_draft": response.content, "messages": new_messages } def notify_mr_hugg(state: EmailState): """Alfred informe M. Hugg de l'email et présente le brouillon de réponse""" email = state["email"] print("\n" + "="*50) print(f"Monsieur, vous avez reçu un email de {email['sender']}.") print(f"Sujet : {email['subject']}") print(f"Catégorie : {state['email_category']}") print("\nJ'ai préparé un brouillon de réponse pour votre révision :") print("-"*50) print(state["email_draft"]) print("="*50 + "\n") # Nous avons fini de traiter cet email return {} ``` ## Étape 3 : Définir notre logique de routage Nous avons besoin d'une fonction pour déterminer quel chemin prendre après la classification : ```python def route_email(state: EmailState) -> str: """Déterminer la prochaine étape basée sur la classification en spam""" if state["is_spam"]: return "spam" else: return "legitimate" ``` > 💡 **Note :** Cette fonction de routage est appelée par LangGraph pour déterminer quelle arête suivre après le nœud de classification. La valeur de retour doit correspondre à l'une des clés dans notre mappage d'arêtes conditionnelles. ## Étape 4 : Créer le *StateGraph* et définir les arêtes Maintenant nous connectons tout ensemble : ```python # Créer le graphe email_graph = StateGraph(EmailState) # Ajouter les nœuds email_graph.add_node("read_email", read_email) email_graph.add_node("classify_email", classify_email) email_graph.add_node("handle_spam", handle_spam) email_graph.add_node("draft_response", draft_response) email_graph.add_node("notify_mr_hugg", notify_mr_hugg) # Commencer les arêtes email_graph.add_edge(START, "read_email") # Ajouter les arêtes - définir le flux email_graph.add_edge("read_email", "classify_email") # Ajouter l'embranchement conditionnel depuis classify_email email_graph.add_conditional_edges( "classify_email", route_email, { "spam": "handle_spam", "legitimate": "draft_response" } ) # Ajouter les arêtes finales email_graph.add_edge("handle_spam", END) email_graph.add_edge("draft_response", "notify_mr_hugg") email_graph.add_edge("notify_mr_hugg", END) # Compiler le graphe compiled_graph = email_graph.compile() ``` Remarquez comment nous utilisons le nœud spécial `END` fourni par LangGraph. Cela indique les états terminaux où le *workflow* se termine. ## Étape 5 : Exécuter l'application Testons notre graphe avec un email légitime et un email spam : ```python # Exemple d'email légitime legitimate_email = { "sender": "john.smith@example.com", "subject": "Question sur vos services", "body": "Cher M. Hugg, J'ai été référé à vous par un collègue et je suis intéressé à en savoir plus sur vos services de conseil. Pourrions-nous programmer un appel la semaine prochaine ? Meilleures salutations, John Smith" } # Exemple d'email spam spam_email = { "sender": "winner@lottery-intl.com", "subject": "VOUS AVEZ GAGNÉ 5 000 000 $ !!!", "body": "FÉLICITATIONS ! Vous avez été sélectionné comme gagnant de notre loterie internationale ! Pour réclamer votre prix de 5 000 000 $, veuillez nous envoyer vos coordonnées bancaires et des frais de traitement de 100 $." } # Traiter l'email légitime print("\nTraitement de l'email légitime...") legitimate_result = compiled_graph.invoke({ "email": legitimate_email, "is_spam": None, "spam_reason": None, "email_category": None, "email_draft": None, "messages": [] }) # Traiter l'email spam print("\nTraitement de l'email spam...") spam_result = compiled_graph.invoke({ "email": spam_email, "is_spam": None, "spam_reason": None, "email_category": None, "email_draft": None, "messages": [] }) ``` ## Étape 6 : Inspecter notre agent trieur d'email avec *Langfuse* 📡 Alors qu'Alfred peaufine l'agent trieur d'email, il se lasse de déboguer ses exécutions. Les agents, par nature, sont imprévisibles et difficiles à inspecter. Mais comme il vise à construire l'agent de détection de spam ultime et à le déployer en production, il a besoin d'une traçabilité robuste pour le *monitoring* et l'analyse futurs. Pour cela, Alfred peut utiliser un outil d'observabilité comme [Langfuse](https://langfuse.com/) pour tracer et monitorer l'agent. Premièrement, nous installons Langfuse avec pip : ```python %pip install -q langfuse ``` Deuxièmement, nous installons LangChain avec pip (LangChain est requis car nous utilisons LangFuse) : ```python %pip install langchain ``` Ensuite, nous ajoutons les clés API LangFuse et l'adresse de l'hôte comme variables d'environnement. Vous pouvez obtenir vos identifiants LangFuse en vous inscrivant sur [LangFuse Cloud](https://cloud.langfuse.com) ou en [auto-hébergeant LangFuse](https://langfuse.com/self-hosting). ```python import os # Obtenez les clés pour votre projet depuis la page des paramètres du projet : https://cloud.langfuse.com os.environ["LANGFUSE_PUBLIC_KEY"] = "pk-lf-..." os.environ["LANGFUSE_SECRET_KEY"] = "sk-lf-..." os.environ["LANGFUSE_HOST"] = "https://cloud.langfuse.com" # 🇪🇺 région EU # os.environ["LANGFUSE_HOST"] = "https://us.cloud.langfuse.com" # 🇺🇸 région US ``` Ensuite, nous configurons le [LangFuse `callback_handler`](https://langfuse.com/docs/integrations/langchain/tracing#add-langfuse-to-your-langchain-application) et instrumentons l'agent en ajoutant le `langfuse_callback` à l'invocation du graphe : `config={"callbacks": [langfuse_handler]}`. ```python from langfuse.langchain import CallbackHandler # Initialiser le CallbackHandler Langfuse pour LangGraph/Langchain (traçage) langfuse_handler = CallbackHandler() # Traiter l'email légitime legitimate_result = compiled_graph.invoke( input={"email": legitimate_email, "is_spam": None, "spam_reason": None, "email_category": None, "draft_response": None, "messages": []}, config={"callbacks": [langfuse_handler]} ) ``` Alfred est maintenant connecté 🔌 ! Les exécutions de LangGraph sont enregistrées dans LangFuse, lui donnant une visibilité complète sur le comportement de l'agent. Avec cette configuration, il est prêt à revisiter les exécutions précédentes et à affiner encore plus son agent de tri de courrier. ![Example trace in Langfuse](https://langfuse.com/images/cookbook/huggingface-agent-course/langgraph-trace-legit.png) _[Lien public vers la trace avec l'email légitime](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/f5d6d72e-20af-4357-b232-af44c3728a7b?timestamp=2025-03-17T10%3A13%3A28.413Z&observation=6997ba69-043f-4f77-9445-700a033afba1)_ ## Visualiser notre graphe LangGraph nous permet de visualiser notre *workflow* pour mieux comprendre et déboguer sa structure : ```python compiled_graph.get_graph().draw_mermaid_png() ``` Mail LangGraph Cela produit une représentation visuelle montrant comment nos nœuds sont connectés et les chemins conditionnels qui peuvent être pris. ## Ce que nous avons construit Nous avons créé un *workflow* complet de traitement des emails qui : 1. Prend un email entrant 2. Utilise un LLM pour le classifier comme spam ou légitime 3. Gère le spam en le rejetant 4. Pour les emails légitimes, rédige une réponse et informe M. Hugg Cela démontre la puissance de LangGraph pour orchestrer des *workflows* complexes avec des LLM tout en maintenant un flux clair et structuré. ## Points clés à retenir - **Gestion d'état** : Nous avons défini un état complet pour suivre tous les aspects du traitement des emails - **Implémentation de nœuds** : Nous avons créé des nœuds fonctionnels qui interagissent avec un LLM - **Routage conditionnel** : Nous avons implémenté une logique d'embranchement basée sur la classification des emails - **États terminaux** : Nous avons utilisé le nœud *END* pour marquer les points d'achèvement dans notre *workflow* ## Et maintenant ? Dans la prochaine section, nous explorerons des fonctionnalités plus avancées de LangGraph, y compris la gestion de l'interaction humaine dans le *workflow* et l'implémentation d'une logique d'embranchement plus complexe basée sur plusieurs conditions. ================================================ FILE: units/fr/unit2/langgraph/introduction.mdx ================================================ # Introduction à LangGraph Unit 2.3 Thumbnail Bienvenue dans cette nouvelle partie de notre voyage, où vous allez apprendre **comment créer des applications** en utilisant le *framework* [`LangGraph`](https://github.com/langchain-ai/langgraph) conçu pour vous aider à structurer et orchestrer des *workflows* complexes avec des LLM. `LangGraph` est un framework qui vous permet de créer des applications **prêtes pour la production** en vous donnant des outils de **contrôle** sur le flux de votre agent. ## Aperçu du module Dans cette unité, vous découvrirez : ### 1️⃣ [Qu'est-ce que LangGraph et quand l'utiliser ?](./when_to_use_langgraph) ### 2️⃣ [Les composants de base de LangGraph](./building_blocks) ### 3️⃣ [Alfred, le majordome trieur de courrier](./first_graph) ### 4️⃣ [Alfred, l'agent d'analyse de documents](./document_analysis_agent) ### 5️⃣ [Quiz](./quiz1) > [!WARNING] > Les exemples de cette section nécessitent l'accès à un modèle LLM/VLM puissant. Nous les avons exécutés en utilisant l'API GPT-4o car elle offre la meilleure compatibilité avec LangGraph. À la fin de cette unité, vous serez en mesure de créer des applications robustes, organisées et prêtes pour la production ! Cela étant dit, cette section est une introduction à LangGraph et des sujets plus avancés peuvent être découverts dans le cours gratuit de la *LangChain academy* : [*Introduction to LangGraph*](https://academy.langchain.com/courses/intro-to-langgraph). Commençons ! ## Ressources - [*LangGraph Agents*](https://langchain-ai.github.io/langgraph/) - Exemples d'agents LangGraph - [*LangChain academy*](https://academy.langchain.com/courses/intro-to-langgraph) - Cours complet sur LangGraph de LangChain ================================================ FILE: units/fr/unit2/langgraph/quiz1.mdx ================================================ # Testez votre compréhension de LangGraph Testons votre compréhension de `LangGraph` avec un quiz rapide ! Cela aidera à renforcer les concepts clés que nous avons couverts jusqu'à présent. Ce quiz est optionnel et il n'est pas noté. ### Q1 : Quel est l'objectif principal de LangGraph ? Quelle déclaration décrit le mieux ce pour quoi LangGraph est conçu ? --- ### Q2 : Dans le contexte du compromis « Contrôle vs Liberté », où se situe LangGraph ? Quelle déclaration caractérise le mieux l'approche de LangGraph pour la conception d'agents ? --- ### Q3 : Quel rôle joue l'état dans LangGraph ? Choisissez la description la plus précise de l'état dans LangGraph. ### Q4 : Qu'est-ce qu'une arête conditionnelle dans LangGraph ? Sélectionnez la description la plus précise. workflow.", correct: true }, { text: "Une arête qui n'est suivie que lorsqu'une condition spécifique se produit", explain: "Les arêtes conditionnelles contrôlent le flux de l'application sur ses sorties, pas sur l'entrée.", }, { text: "Une arête qui nécessite une confirmation utilisateur avant de continuer", explain: "Les arêtes conditionnelles sont basées sur des conditions programmatiques, pas sur des exigences d'interaction utilisateur.", } ]} /> --- ### Q5 : Comment LangGraph aide-t-il à résoudre le problème d'hallucination dans les LLM ? Choisissez la meilleure réponse. Félicitations pour avoir terminé le quiz ! 🎉 Si vous avez manqué des questions, considérez réviser les sections précédentes pour renforcer votre compréhension. Ensuite, nous explorerons des fonctionnalités plus avancées de LangGraph et verrons comment construire des *workflows* d'agents plus complexes. ================================================ FILE: units/fr/unit2/langgraph/when_to_use_langgraph.mdx ================================================ # Qu'est-ce que LangGraph ? `LangGraph` est un *framework* développé par [LangChain](https://www.langchain.com/) **pour gérer le flux de contrôle des applications qui intègrent un LLM**. ## `LangGraph` est-il différent de `LangChain` ? LangChain fournit une interface standard pour interagir avec les modèles et autres composants, utile pour la récupération, les appels de LLM et les appels d'outils. Les classes de LangChain peuvent être utilisées dans LangGraph, mais ne DOIVENT PAS nécessairement être utilisées. Les *packages* sont différents et peuvent être utilisés de manière isolée, mais, au final, toutes les ressources que vous trouverez en ligne utilisent les deux *packages* main dans la main. ## Quand dois-je utiliser `LangGraph` ? ### Contrôle vs. liberté Lors de la conception d'applications IA, vous faites face à un compromis fondamental entre **contrôle** et **liberté** : - La **liberté** donne à votre LLM plus d'espace pour être créatif et s'attaquer à des problèmes inattendus. - Le **contrôle** vous permet d'assurer un comportement prévisible et de maintenir des garde-fous. Les agents à code, comme ceux que vous pouvez rencontrer dans *smolagents*, sont très libres. Ils peuvent appeler plusieurs outils en une seule étape d'action, créer leurs propres outils, etc. Cependant, ce comportement peut les rendre moins prévisibles et moins contrôlables qu'un agent standard travaillant avec un *JSON* ! `LangGraph` est à l'autre extrémité du spectre, il brille lorsque vous avez besoin de **contrôle** sur l'exécution de votre agent. Il vous donne les outils pour créer une application qui suit un processus prévisible tout en exploitant toujours la puissance des LLM. En termes simples, si votre application implique une série d'étapes qui doivent être orchestrées d'une manière spécifique, avec des décisions prises à chaque point de jonction, **LangGraph fournit la structure dont vous avez besoin**. À titre d'exemple, disons que nous voulons créer un assistant LLM qui peut répondre à quelques questions sur certains documents. Comme les LLM comprennent mieux le texte, avant de pouvoir répondre à la question, vous devrez convertir d'autres modalités complexes (graphiques, tableaux) en texte. Cependant, ce choix dépend du type de document que vous avez ! C'est un embranchement que j'ai choisi de représenter comme suit : Control flow > 💡 **Astuce :** La partie gauche n'est pas un agent, car ici aucun appel d'outil n'est impliqué. Mais la partie droite devra écrire du code pour interroger le *xls* (convertir en *pandas* et le manipuler). Bien que cet embranchement soit déterministe, vous pouvez également concevoir un embranchement conditionné par la sortie d'un LLM, les rendant indéterministes. Les scénarios clés où LangGraph excelle incluent : - **Le processus de raisonnement en plusieurs étapes** qui nécessitent un contrôle explicite sur le flux - **Des applications nécessitant la persistance de l'état** entre les étapes - **Des systèmes qui combinent la logique déterministe avec les capacités d'une IA** - ***Des workflows* qui nécessitent des interventions *human-in-the-loop*** - **Des architectures d'agents complexes** avec plusieurs composants travaillant ensemble En substance, chaque fois que cela est possible, en tant qu'être humain, concevez un flux d'actions basé sur les résultats de chaque action, et décidez de ce qu'il faut exécuter ensuite en conséquence. Dans ce cas, LangGraph est le bon *framework* pour vous ! `LangGraph` est, à mon avis, le *framework* d'agents le plus prêt pour la production sur le marché. ## Comment fonctionne LangGraph ? Au cœur de `LangGraph` se trouve une structure de graphe dirigé pour définir le flux de votre application : - **Les nœuds** représentent des étapes de traitement individuelles (comme appeler un LLM, utiliser un outil, ou prendre une décision). - **Les arêtes** définissent les transitions possibles entre les étapes. - **L'état** est défini par l'utilisateur et maintenu et transmis entre les nœuds pendant l'exécution. Lors de la décision du prochain nœud à cibler, c'est l'état actuel que nous regardons. Nous explorerons ces blocs fondamentaux plus en détail dans le prochain chapitre ! ## En quoi est-ce différent du Python standard ? Pourquoi ai-je besoin de LangGraph ? Vous pourriez vous demander : « Je pourrais juste écrire du code Python standard avec des instructions *if-else* pour gérer tous ces flux, non ? » Bien que techniquement vrai, LangGraph offre **certains avantages** par rapport au Python standard pour créer des systèmes complexes. Vous pourriez créer la même application sans LangGraph, mais il construit des outils et des abstractions plus faciles pour vous. Il inclut des états, une visualisation, une journalisation (traces), de l'*human-in-the-loop* intégré, et plus encore. ================================================ FILE: units/fr/unit2/llama-index/README.md ================================================ # Table des matières Ce plan de chapitre LlamaIndex fait partie de l'unité 2 du cours. Vous pouvez accéder à l'unité 2 sur LlamaIndex sur hf.co/learn 👉 ici | Titre | Description | | --- | --- | | [Introduction](introduction.mdx) | Introduction à LlamaIndex | | [LlamaHub](llama-hub.mdx) | LlamaHub : un registre d'intégrations, d'agents et de tools | | [Components](components.mdx) | Components : les blocs de construction des workflows | | [Tools](tools.mdx) | Tools : comment construire des tools dans LlamaIndex | | [Quiz 1](quiz1.mdx) | Quiz 1 | | [Agents](agents.mdx) | Agents : comment construire des agents dans LlamaIndex | | [Workflows](workflows.mdx) | Workflows : une séquence d'étapes, d'événements composés de components qui sont exécutés dans l'ordre | | [Quiz 2](quiz2.mdx) | Quiz 2 | | [Conclusion](conclusion.mdx) | Conclusion | ================================================ FILE: units/fr/unit2/llama-index/agents.mdx ================================================ # Utiliser les agents dans LlamaIndex Vous vous souvenez d'Alfred, notre agent majordome serviable d'avant ? Eh bien, il va recevoir une mise à niveau ! Maintenant que nous comprenons les outils disponibles dans LlamaIndex, nous pouvons lui donner de nouvelles capacités pour mieux nous servir. Mais avant de continuer, rappelons-nous ce qui fait fonctionner un agent comme Alfred. Dans l'Unité 1, nous avons appris que : > Un agent est un système qui exploite un modèle d'IA pour interagir avec son environnement afin d'atteindre un objectif défini par l'utilisateur. Il combine le raisonnement, la planification et l'exécution d'actions (souvent via des outils externes) pour accomplir des tâches. LlamaIndex prend en charge **trois types principaux d'agents avec raisonnement** : ![Agents](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/agents.png) 1. `Function Calling Agents` : Ceux-ci fonctionnent avec des modèles qui peuvent appeler des fonctions spécifiques. 2. `ReAct Agents` : Ceux-ci peuvent fonctionner avec n'importe quel modèle qui fait du *chat* ou des *endpoints* de texte et traiter des tâches de raisonnement complexes. 3. `Advanced Custom Agents` : Ceux-ci utilisent des méthodes plus complexes pour traiter des tâches et *workflows* plus complexes. > [!TIP] > Trouvez plus d'informations sur les agents avancés sur BaseWorkflowAgent. ## Initialiser les agents > [!TIP] > Vous pouvez suivre le code dans ce notebook que vous pouvez exécuter avec Google Colab. Pour créer un agent, nous commençons par lui fournir un **ensemble de fonctions/outils qui définissent ses capacités**. Regardons comment créer un agent avec quelques outils de base. Au moment de la rédaction, l'agent utilisera automatiquement l'API d'appel de fonctions (si disponible), ou une boucle d'agent ReAct standard. Les LLM prennant en charge une API outils/fonctions sont relativement nouveaux, mais ils fournissent un moyen puissant d'appeler des outils en évitant de devoir utiliser un *prompt* spécifique et permettant au LLM de créer des appels d'outils basés sur des schémas fournis. Les agents ReAct sont également bons pour les tâches de raisonnement complexes et peuvent fonctionner avec n'importe quel LLM qui a des capacités de chat ou de complétion de texte. Ils sont plus verbeux et montrent le raisonnement derrière certaines actions qu'ils prennent. ```python from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI from llama_index.core.agent.workflow import AgentWorkflow from llama_index.core.tools import FunctionTool # define example de Tool -- type annotations, noms de fonctions, et docstrings, sont tous inclus dans les schémas analysés ! def multiply(a: int, b: int) -> int: """Multiplies two integers and returns the resulting integer""" return a * b # initialisation du llm llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") # initialisation de l'agent agent = AgentWorkflow.from_tools_or_functions( [FunctionTool.from_defaults(multiply)], llm=llm ) ``` **Les agents sont sans état par défaut**, ajouter la mémorisation des interactions passées est optionnel en utilisant un objet `Context`. Cela pourrait être utile si vous voulez utiliser un agent qui a besoin de se souvenir des interactions précédentes, comme un *chatbot* qui maintient le contexte à travers plusieurs messages ou un gestionnaire de tâches qui a besoin de suivre les progrès au fil du temps. ```python # sans état response = await agent.run("What is 2 times 2?") # se souvenir de l'état from llama_index.core.workflow import Context ctx = Context(agent) response = await agent.run("My name is Bob.", ctx=ctx) response = await agent.run("What was my name again?", ctx=ctx) ``` Vous remarquerez que les agents dans `LlamaIndex` sont asynchrones car ils utilisent l'opérateur `await` de Python. Si vous débuté avec le code asynchrone en Python, ou avez besoin d'un rappel, LlamaIndex dispose d'un [excellent guide sur le sujet](https://docs.llamaindex.ai/en/stable/getting_started/async_python/). Maintenant que nous avons les bases, jetons un coup d'œil à comment nous pouvons utiliser des outils plus complexes dans nos agents. ## Créer des agents de RAG avec des *QueryEngineTools* **Le RAG agentique est un moyen puissant d'utiliser des agents pour répondre à des questions sur vos données.** Nous pouvons passer divers outils à Alfred pour l'aider à répondre aux questions. Cependant, au lieu de répondre automatiquement à la question au-dessus des documents, Alfred peut décider d'utiliser n'importe quel autre outil ou flux pour répondre à la question. ![Agentic RAG](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/agentic-rag.png) Il est facile d'**envelopper `QueryEngine` comme un outil** pour un agent. Ce faisant, nous devons **définir un nom et une description**. Le LLM utilisera ces informations pour utiliser correctement l'outil. Voyons comment charger un `QueryEngineTool` en utilisant le `QueryEngine` que nous avons créé dans la [section des *components*](components). ```python from llama_index.core.tools import QueryEngineTool query_engine = index.as_query_engine(llm=llm, similarity_top_k=3) # comme indiqué dans la section Composants de LlamaIndex query_engine_tool = QueryEngineTool.from_defaults( query_engine=query_engine, name="name", description="a specific description", return_direct=False, ) query_engine_agent = AgentWorkflow.from_tools_or_functions( [query_engine_tool], llm=llm, system_prompt="You are a helpful assistant that has access to a database containing persona descriptions." ) ``` ## Créer des systèmes multi-agents La classe `AgentWorkflow` prend également en charge directement les systèmes multi-agents. En donnant à chaque agent un nom et une description, le système maintient un seul orateur actif, chaque agent ayant la capacité de passer le relais à un autre agent. En rétrécissant la portée de chaque agent, nous pouvons aider à augmenter leur précision générale lors de la réponse aux messages des utilisateurs. **Les agents dans LlamaIndex peuvent également être directement utilisés comme outils** pour d'autres agents, pour des scénarios plus complexes et personnalisés. ```python from llama_index.core.agent.workflow import ( AgentWorkflow, FunctionAgent, ReActAgent, ) # Définir quelques outils def add(a: int, b: int) -> int: """Add two numbers.""" return a + b def subtract(a: int, b: int) -> int: """Subtract two numbers.""" return a - b # Créer les configurations de l'agent # NOTE : nous pouvons utiliser FunctionAgent ou ReActAgent ici. # FunctionAgent fonctionne pour les LLM avec une API d'appel de fonction. # ReActAgent fonctionne pour n'importe quel LLM. calculator_agent = ReActAgent( name="calculator", description="Performs basic arithmetic operations", system_prompt="You are a calculator assistant. Use your tools for any math operation.", tools=[add, subtract], llm=llm, ) query_agent = ReActAgent( name="info_lookup", description="Looks up information about XYZ", system_prompt="Use your tool to query a RAG system to answer information about XYZ", tools=[query_engine_tool], llm=llm ) # Créer et exécuter le workflow agent = AgentWorkflow( agents=[calculator_agent, query_agent], root_agent="calculator" ) # Exécuter le système response = await agent.run(user_msg="Can you add 5 and 3?") ``` > [!TIP] > Vous n'avez pas encore assez appris ? Il y a beaucoup plus à découvrir sur les agents et les outils dans LlamaIndex dans l'Introduction de base à AgentWorkflow ou le Guide d'apprentissage sur les agents, où vous pouvez lire plus sur le streaming, la sérialisation de contexte, et l'humain dans la boucle ! Maintenant que nous comprenons les bases des agents et des outils dans LlamaIndex, voyons comment nous pouvons utiliser LlamaIndex pour **créer des *workflows* configurables et gérables !** ================================================ FILE: units/fr/unit2/llama-index/components.mdx ================================================ # Que sont les *components* dans LlamaIndex ? Vous vous souvenez d'Alfred, notre agent majordome serviable de l'Unité 1 ? Pour nous aider efficacement, Alfred doit comprendre nos demandes et **préparer, trouver et utiliser les informations pertinentes pour aider à accomplir les tâches.** C'est là que les *components* de LlamaIndex entrent en jeu. Bien que LlamaIndex ait de nombreux *components*, **nous nous concentrerons spécifiquement sur le *component* `QueryEngine`.** Pourquoi ? Parce qu'il peut être utilisé comme un outil de *Retrieval-Augmented Generation* (RAG) pour un agent. Alors, qu'est-ce que le RAG ? Les LLM sont entraînés sur d'énormes corpus de données pour apprendre les connaissances générales. Cependant, ils peuvent ne pas être entraînés sur des données pertinentes et à jour. Le RAG résout ce problème en trouvant et récupérant des informations pertinentes de vos données et en les donnant au LLM. ![RAG](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/rag.png) Maintenant, pensez à comment Alfred fonctionne : 1. Vous demandez à Alfred d'aider à planifier un dîner 2. Alfred doit vérifier votre calendrier, vos préférences alimentaires et les menus précédents réussis 3. Le `QueryEngine` aide Alfred à trouver ces informations et à les utiliser pour planifier le dîner Cela fait du `QueryEngine` **un *component* clé pour construire des *workflows* de RAG agentiques** dans LlamaIndex. Tout comme Alfred a besoin de rechercher dans les informations de votre maison pour être utile, tout agent a besoin d'un moyen de trouver et comprendre des données pertinentes. Le `QueryEngine` fournit exactement cette capacité. Maintenant, approfondissons un peu les *components* et voyons comment vous pouvez **combiner les *components* pour créer un pipeline de RAG.** ## Créer un pipeline de RAG en utilisant des *components* > [!TIP] > Vous pouvez suivre le code dans ce notebook que vous pouvez exécuter avec Google Colab. Il y a cinq étapes clés dans le RAG, qui feront partie de la plupart des applications plus ambitieuses que vous construirez. A savoir : 1. **Chargement** : cela se réfère à obtenir vos données d'où elles vivent (qu'il s'agisse de fichiers texte, de PDF, d'un autre site web, d'une base de données, ou d'une API) dans votre *workflow*. *LlamaHub* fournit des centaines d'intégrations parmi lesquelles choisir. 2. **Indexation** : cela signifie créer une structure de données qui permet d'interroger les données. Pour les LLM, cela signifie presque toujours créer des *embeddings* vectoriels. Ce sont des représentations numériques de la signification des données. L'indexation peut également se référer à de nombreuses autres stratégies de métadonnées pour faciliter la recherche de données contextuellement pertinentes basées sur les propriétés. 3. **Stockage** : une fois vos données indexées, vous voudrez stocker votre index, ainsi que d'autres métadonnées, pour éviter de devoir ré-indexer à chaque utilisation. 4. **Requête** : pour toute stratégie d'indexation donnée, il y a de nombreuses façons d'utiliser les LLM et les structures de données LlamaIndex pour faire des requêtes, incluant des sous-requêtes, des requêtes multi-étapes et des stratégies hybrides. 5. **Évaluation** : une étape critique dans tout flux est de vérifier son efficacité par rapport à d'autres stratégies, ou lorsque vous apportez des modifications. L'évaluation fournit des mesures objectives de la précision, de la fidélité et de la rapidité de vos réponses aux requêtes. Ensuite, voyons comment nous pouvons reproduire ces étapes en utilisant des *components*. ### Chargement et intégration des documents Comme mentionné précédemment, LlamaIndex peut fonctionner au-dessus de vos propres données, cependant, **avant d'accéder aux données, nous devons les charger.** Il y a trois façons principales de charger des données dans LlamaIndex : 1. `SimpleDirectoryReader` : Un chargeur de données intégré pour divers types de fichiers d'un répertoire local. 2. `LlamaParse` : L'outil officiel de LlamaIndex pour l'analyse de PDF, disponible comme une API gérée. 3. `LlamaHub` : Un registre de centaines de bibliothèques de chargement de données pour ingérer des données de n'importe quelle source. > [!TIP] > Familiarisez-vous avec les chargeurs de données LlamaHub et le parser LlamaParse pour des sources de données plus complexes. **La façon la plus simple de charger des données est avec `SimpleDirectoryReader`.** Ce *component* polyvalent peut charger divers types de fichiers d'un dossier et les convertir en objets `Document` avec lesquels LlamaIndex peut travailler. Voyons comment nous pouvons utiliser `SimpleDirectoryReader` pour charger des données d'un dossier. ```python from llama_index.core import SimpleDirectoryReader reader = SimpleDirectoryReader(input_dir="path/to/directory") documents = reader.load_data() ``` Après avoir chargé nos documents, nous devons les diviser en plus petites parties appelées objets `Node`. Un `Node` est juste un morceau de texte du document original qui est plus facile à traiter pour l'IA, tout en conservant des références à l'objet `Document` original. L'`IngestionPipeline` nous aide à créer ces *nodes* grâce à deux transformations clés. 1. `SentenceSplitter` divise les documents en morceaux aux niveaux des phrases. 2. `HuggingFaceEmbedding` convertit chaque morceau en *embeddings* numériques. Ce processus nous aide à organiser nos documents d'une manière qui est plus utile pour la recherche et l'analyse. ```python from llama_index.core import Document from llama_index.embeddings.huggingface import HuggingFaceEmbedding from llama_index.core.node_parser import SentenceSplitter from llama_index.core.ingestion import IngestionPipeline # créer le pipeline avec les transformations pipeline = IngestionPipeline( transformations=[ SentenceSplitter(chunk_overlap=0), HuggingFaceEmbedding(model_name="BAAI/bge-small-en-v1.5"), ] ) nodes = await pipeline.arun(documents=[Document.example()]) ``` ### Stockage et indexation des documents Après avoir créé nos objets `Node`, nous devons les indexer pour les rendre recherchables, mais avant de pouvoir le faire, nous avons besoin d'un endroit pour stocker nos données. Puisque nous utilisons un pipeline d'ingestion, nous pouvons directement attacher un *vector store* au pipeline pour le remplir. Dans ce cas, nous utiliserons `Chroma` pour stocker nos documents.
Installer ChromaDB Comme introduit dans la section sur le LlamaHub, nous pouvons installer le *vector store* ChromaDB avec la commande suivante : ```bash pip install llama-index-vector-stores-chroma ```
```python import chromadb from llama_index.vector_stores.chroma import ChromaVectorStore db = chromadb.PersistentClient(path="./alfred_chroma_db") chroma_collection = db.get_or_create_collection("alfred") vector_store = ChromaVectorStore(chroma_collection=chroma_collection) pipeline = IngestionPipeline( transformations=[ SentenceSplitter(chunk_size=25, chunk_overlap=0), HuggingFaceEmbedding(model_name="BAAI/bge-small-en-v1.5"), ], vector_store=vector_store, ) ``` > [!TIP] > Un aperçu des différents vector stores peut être trouvé dans la documentation de LlamaIndex. C'est là que les *embeddings* vectoriels entrent en jeu. En enchassant à la fois la requête et les *nodes* dans le même espace vectoriel, nous pouvons trouver des correspondances pertinentes. Le `VectorStoreIndex` s'occupe de cela pour nous, en utilisant le même modèle d'*embedding* que nous avons utilisé pendant l'ingestion pour assurer la cohérence. Voyons comment créer cet index à partir de notre *vector store* et des *embeddings* : ```python from llama_index.core import VectorStoreIndex from llama_index.embeddings.huggingface import HuggingFaceEmbedding embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-small-en-v1.5") index = VectorStoreIndex.from_vector_store(vector_store, embed_model=embed_model) ``` Toutes les informations sont automatiquement persistées dans l'objet `ChromaVectorStore` et le chemin du répertoire passé. Parfait ! Maintenant que nous pouvons sauvegarder et charger notre index facilement, explorons comment l'interroger de différentes manières. ### Interroger un *VectorStoreIndex* avec des *prompts* et des LLM Avant de pouvoir interroger notre index, nous devons le convertir en interface de requête. Les options de conversion les plus courantes sont : - `as_retriever` : Pour la récupération basique de documents, retournant une liste d'objets `NodeWithScore` avec des scores de similarité - `as_query_engine` : Pour les interactions question-réponse simples, retournant une réponse écrite - `as_chat_engine` : Pour les interactions conversationnelles qui maintiennent la mémoire à travers plusieurs messages, retournant une réponse écrite utilisant l'historique de chat et le contexte indexé Nous nous concentrerons sur le *query engine* car il est plus commun pour les interactions de type agent. Nous passons également un LLM au *query engine* à utiliser pour la réponse. ```python from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") query_engine = index.as_query_engine( llm=llm, response_mode="tree_summarize", ) query_engine.query("What is the meaning of life?") # Le sens de la vie est 42 ``` ### Traitement des réponses Sous le capot, le *query engine* n'utilise pas seulement le LLM pour répondre à la question mais utilise également un `ResponseSynthesizer` comme stratégie pour traiter la réponse. Encore une fois, c'est entièrement personnalisable mais il y a trois stratégies principales qui fonctionnent bien prêtes à l'emploi : - `refine` : créer et affiner une réponse en parcourant séquentiellement chaque morceau de texte récupéré. Cela fait un appel au LLM séparé pour chaque *Node*/morceau récupéré. - `compact` (par défaut) : similaire à l'affinement mais concaténant les morceaux au préalable, résultant en moins d'appels au LLM. - `tree_summarize` : créer une réponse détaillée en parcourant chaque morceau de texte récupéré et créant une structure d'arbre de la réponse. > [!TIP] > Prenez un contrôle fin de vos workflows de requête avec l'API de composition de bas niveau. Cette API vous permet de personnaliser et de finetuner chaque étape du processus de requête pour correspondre à vos besoins exacts, ce qui se marie également très bien avec les Workflows. Le modèle de langage ne performera pas toujours de manière prévisible, donc nous ne pouvons pas être sûrs que la réponse que nous obtenons soit toujours correcte. Nous pouvons gérer cela en **évaluant la qualité de la réponse**. ### Évaluation et observabilité LlamaIndex fournit **des outils d'évaluation intégrés pour évaluer la qualité des réponses.** Ces évaluateurs exploitent les LLM pour analyser les réponses à travers différentes dimensions. Regardons les trois évaluateurs principaux disponibles : - `FaithfulnessEvaluator` : Évalue la fidélité de la réponse en vérifiant si la réponse est supportée par le contexte. - `AnswerRelevancyEvaluator` : Évalue la pertinence de la réponse en vérifiant si la réponse est pertinente par rapport à la question. - `CorrectnessEvaluator` : Évalue la correction de la réponse en vérifiant si la réponse est correcte. > [!TIP] > Vous voulez en savoir plus sur l'observabilité et l'évaluation des agents ? Suivez l'Unité Bonus 2. ```python from llama_index.core.evaluation import FaithfulnessEvaluator query_engine = # de la section précédente llm = # de la section précédente # index des requêtes evaluator = FaithfulnessEvaluator(llm=llm) response = query_engine.query( "What battles took place in New York City in the American Revolution?" ) eval_result = evaluator.evaluate_response(response=response) eval_result.passing ``` Même sans évaluation directe, nous pouvons **obtenir des informations sur la performance de notre système grâce à l'observabilité.** Ceci est particulièrement utile quand nous construisons des *workflows* plus complexes et que nous voulons comprendre comment chaque *component* performe.
Installer LlamaTrace Comme introduit dans la section sur le LlamaHub, nous pouvons installer le *callback* LlamaTrace d'Arize Phoenix avec la commande suivante : ```bash pip install -U llama-index-callbacks-arize-phoenix ``` De plus, nous devons définir la variable d'environnement `PHOENIX_API_KEY` avec notre clé API LlamaTrace. Nous pouvons l'obtenir en : - Créant un compte sur [LlamaTrace](https://llamatrace.com/login) - Générant une clé API dans les paramètres de votre compte - Utilisant la clé API dans le code ci-dessous pour activer le *tracking*
```python import llama_index import os PHOENIX_API_KEY = "" os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = f"api_key={PHOENIX_API_KEY}" llama_index.core.set_global_handler( "arize_phoenix", endpoint="https://llamatrace.com/v1/traces" ) ``` > [!TIP] > Vous voulez en savoir plus sur les components et comment les utiliser ? Continuez votre parcours avec les Guides des components ou le Guide sur le RAG. Nous avons vu comment utiliser les *components* pour créer un `QueryEngine`. Maintenant, voyons comment nous pouvons **utiliser le `QueryEngine` comme un outil pour un agent !** ================================================ FILE: units/fr/unit2/llama-index/conclusion.mdx ================================================ # Conclusion Félicitations pour avoir terminé le module `llama-index` de cette deuxième Unité 🥳 Vous **maîtrisez les fondamentaux** de `llama-index` et avez vu comment construire vos propres *workflows* agentiques ! Maintenant que vous avez des compétences en `llama-index`, vous pouvez commencer à créer des moteurs de recherche qui résoudront des tâches qui vous intéressent. Dans le prochain module de l'unité, vous allez apprendre **comment construire des *agents* avec *LangGraph***. Enfin, nous aimerions **entendre ce que vous pensez du cours et comment nous pouvons Enfin, nous serions ravis **d'entendre ce que vous pensez du cours et comment nous pourrions l'améliorer**. Si vous avez des retours, n'hésitez pas à [remplir ce formulaire](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog). ### Continuez à apprendre, restez géniaux 🤗 ================================================ FILE: units/fr/unit2/llama-index/introduction.mdx ================================================ # Introduction à LlamaIndex Bienvenue dans ce module, où vous allez apprendre à créer des agents propulsés par des LLM en utilisant la boîte à outils [LlamaIndex](https://www.llamaindex.ai/). LlamaIndex est **une boîte à outils complète pour créer des agents sur vos données en utilisant des index et des *workflows***. Pour ce cours, nous nous concentrerons sur trois parties principales qui aident à construire des agents dans LlamaIndex : **les *Components***, **les *Agents* et *Tools*** et **les *Workflows***. ![LlamaIndex](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/thumbnail.png) Examinons ces parties clés de LlamaIndex et comment elles aident avec les agents : - **Les *Components*** : Ce sont les blocs de construction de base que vous utilisez dans LlamaIndex. Ceux-ci incluent des éléments comme les *prompts*, les modèles et les bases de données. Les *components* aident souvent à connecter LlamaIndex avec d'autres outils et bibliothèques. - **Les *Tools*** : Les *tools* sont des *components* qui fournissent des capacités spécifiques comme la recherche, le calcul ou l'accès à des services externes. Ce sont les blocs de construction qui permettent aux agents d'effectuer des tâches. - **Les *Agents*** : Les *agents* sont des *components* autonomes qui peuvent utiliser des *tools* et prendre des décisions. Ils coordonnent l'utilisation des *tools* pour accomplir des objectifs complexes. - **Les *Workflows*** : Ce sont des processus étape par étape qui traitent la logique ensemble. Les *workflows* ou *agentic workflows* sont un moyen de structurer le comportement agentique sans l'utilisation explicite d'*agents*. ## Qu'est-ce qui rend LlamaIndex spécial ? Bien que LlamaIndex fasse certaines choses similaires à d'autres *frameworks* comme *smolagents*, il présente quelques avantages clés : - **Système de *workflow* clair** : Les *workflows* aident à décomposer comment les agents doivent prendre des décisions étape par étape en utilisant une syntaxe événementielle et asynchrone. Cela vous aide à composer et organiser clairement votre logique. - ***Parsing* avancé de documents avec *LlamaParse*** : *LlamaParse* a été créé spécifiquement pour LlamaIndex, donc l'intégration est transparente, bien que ce soit une fonctionnalité payante. - **Nombreux *Components* prêts à l'emploi** : LlamaIndex existe depuis un certain temps, donc il fonctionne avec beaucoup d'autres *frameworks*. Cela signifie qu'il dispose de nombreux *components* testés et fiables, comme des LLM, des *retrievers*, des index, et plus encore. - ***LlamaHub*** : est un registre de centaines de ces *components*, *agents* et *outils* que vous pouvez utiliser dans LlamaIndex. Tous ces concepts sont nécessaires dans différents scénarios pour créer des agents utiles. Dans les sections suivantes, nous examinerons chacun de ces concepts en détail. Après avoir acquis la maîtrise les concepts, nous utiliserons nos nouvelles connaissances pour **créer des cas d'usage appliqués avec Alfred l'agent** ! Prendre en main sur LlamaIndex est excitant, n'est-ce pas ? Alors, qu'attendons-nous ? Commençons par **trouver et installer les intégrations dont nous avons besoin en utilisant *LlamaHub* ! 🚀** ================================================ FILE: units/fr/unit2/llama-index/llama-hub.mdx ================================================ # Introduction au *LlamaHub* ***LlamaHub* est un registre de centaines d'intégrations, d'*agents* et d'*outils* que vous pouvez utiliser dans LlamaIndex.** ![LlamaHub](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/llama-hub.png) Nous utiliserons diverses intégrations dans ce cours, alors examinons d'abord le *LlamaHub* et comment il peut nous aider. Voyons comment trouver et installer les dépendances pour les *components* dont nous avons besoin. ## Installation Les instructions d'installation de LlamaIndex sont disponibles comme un **aperçu bien structuré sur [*LlamaHub*](https://llamahub.ai/)**. Cela peut être un peu démoralisant au début, mais la plupart des **commandes d'installation suivent généralement un format facile à retenir** : ```bash pip install llama-index-{component-type}-{framework-name} ``` Essayons d'installer les dépendances pour un *component* *LLM* et *embedding* en utilisant l'[intégration de l'API d'inférence *Hugging Face*](https://llamahub.ai/l/llms/llama-index-llms-huggingface-api?from=llms). ```bash pip install llama-index-llms-huggingface-api llama-index-embeddings-huggingface ``` ## Utilisation Une fois installé, nous pouvons voir les motifs d'utilisation. Vous remarquerez que les chemins d'importation suivent la commande d'installation ! Ci-dessous, nous pouvons voir un exemple d'utilisation de **l'API d'inférence Hugging Face pour un *component* LLM**. ```python from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI import os from dotenv import load_dotenv # Charger le fichier .env load_dotenv() # Récupérer HF_TOKEN à partir des variables d'environnement hf_token = os.getenv("HF_TOKEN") llm = HuggingFaceInferenceAPI( model_name="Qwen/Qwen2.5-Coder-32B-Instruct", temperature=0.7, max_tokens=100, token=hf_token, ) response = llm.complete("Hello, how are you?") print(response) # Je suis bon, comment puis-je vous aider aujourd'hui ? ``` Parfait, nous savons maintenant comment trouver, installer et utiliser les intégrations pour les *components* dont nous avons besoin. **Approfondissons les *components*** et voyons comment nous pouvons les utiliser pour construire nos propres agents. ================================================ FILE: units/fr/unit2/llama-index/quiz1.mdx ================================================ # Quiz rapide 1 (non noté) [[quiz1]] Jusqu'à présent, nous avons discuté des *components* et outils clés utilisés dans LlamaIndex. Il est temps de faire un petit quiz, car **se tester soi-même** est la meilleure façon d'apprendre et [d'éviter l'illusion de compétence](https://www.coursera.org/lecture/learning-how-to-learn/illusions-of-competence-BuFzf). Cela vous aidera à trouver **où vous devez renforcer vos connaissances**. Ceci est un quiz optionnel et il n'est pas noté. ### Q1 : Qu'est-ce qu'un `QueryEngine` ? Laquelle des affirmations suivantes décrit le mieux un *component* `QueryEngine` ? QueryEngine doit être capable de récupérer et traiter des informations pertinentes.", }, { text: "Un component qui trouve et récupère des informations pertinentes dans le cadre du processus de RAG.", explain: "Cela capture l'objectif principal d'un QueryEngine.", correct: true }, { text: "Un outil qui ne fait que stocker des embeddings vectoriels sans fonctionnalité de recherche.", explain: "Un QueryEngine fait plus que simplement stocker des embeddings ; il recherche et récupère activement des informations.", }, { text: "Un component qui évalue uniquement la qualité des réponses.", explain: "L'évaluation est séparée de l'objectif principal de récupération du QueryEngine.", } ]} /> --- ### Q2 : Quel est le but des `FunctionTools` ? Pourquoi les FunctionTools sont-ils importants pour un agent ? FunctionTools ne sont pas principalement pour le stockage de données.", }, { text: "Pour convertir des fonctions Python en outils qu'un agent peut utiliser.", explain: "Les FunctionTools enveloppent les fonctions Python pour les rendre accessibles aux agents.", correct: true }, { text: "Pour permettre aux agents de créer des définitions de fonctions aléatoires.", explain: "Les FunctionTools servent l'objectif spécifique de rendre les fonctions disponibles aux agents.", }, { text: "Pour traiter uniquement des données textuelles.", explain: "Les FunctionTools peuvent fonctionner avec différents types de fonctions, pas seulement le traitement de texte.", } ]} /> --- ### Q3 : Que sont les `Toolspecs` dans LlamaIndex ? Quel est l'objectif principal des `Toolspecs` ? Toolspecs servent un objectif important dans l'écosystème LlamaIndex.", }, { text: "Ce sont des ensembles d'outils créés par la communauté qui étendent les capacités des agents.", explain: "Les Toolspecs permettent à la communauté de partager et réutiliser des outils.", correct: true }, { text: "Ils sont utilisés uniquement pour la gestion mémoire.", explain: "Les Toolspecs concernent la fourniture d'outils, pas la gestion mémoire.", }, { text: "Ils ne fonctionnent qu'avec le traitement de texte.", explain: "Les Toolspecs peuvent inclure différents types d'outils, pas seulement le traitement de texte.", } ]} /> --- ### Q4 : Qu'est-ce qui est requis pour créer un outil ? Quelles informations doivent être incluses lors de la création d'un outil ? docstring.", }, { text: "Seul le nom est requis.", explain: "Une fonction et une description/docstring sont également requises pour une documentation appropriée de l'outil.", }, { text: "Seule la description est requise.", explain: "Une fonction est requise pour que nous ayons du code à exécuter quand un agent sélectionne un outil", }, { text: "Seule la fonction est requise.", explain: "Le nom et la description sont par défaut le nom et la docstring de la fonction fournie", correct: true } ]} /> --- Félicitations pour avoir terminé ce Quiz 🥳, si vous avez manqué certains éléments, prenez le temps de relire le chapitre pour renforcer vos connaissances. Si vous le réussissez, vous êtes prêt à plonger plus profondément dans la construction avec ces *components* ! ================================================ FILE: units/fr/unit2/llama-index/quiz2.mdx ================================================ # Quiz rapide 2 (non noté) [[quiz2]] Quoi ?! Un autre Quiz ? Nous savons, nous savons, ... 😅 Mais ce court quiz non noté est là pour **vous aider à renforcer les concepts clés que vous venez d'apprendre**. Ce quiz couvre les *workflows* d'agents et les interactions, composants essentiels pour construire des agents efficaces. ### Q1 : Quel est le but de l'`AgentWorkflow` dans LlamaIndex ? AgentWorkflow est la façon principale de créer rapidement un système avec un ou plusieurs agents.", correct: true }, { text: "Pour créer un seul agent qui peut interroger vos données sans mémoire", explain: "Non, l'AgentWorkflow est peut faire plus que cela, le QueryEngine est pour des requêtes simples sur vos données.", }, { text: "Pour construire automatiquement des outils pour les agents", explain: "L'AgentWorkflow ne construit pas d'outils, c'est le travail du développeur.", }, { text: "Pour gérer la mémoire et l'état des agents", explain: "Gérer la mémoire et l'état n'est pas l'objectif principal de l'AgentWorkflow.", } ]} /> --- ### Q2 : Quel objet est utilisé pour garder une trace de l'état du *workflow* ? State", explain: "State n'est pas le bon objet pour la gestion d'état du workflow.", }, { text: "Context", explain: "Context est le bon objet utilisé pour garder une trace de l'état du workflow.", correct: true }, { text: "WorkflowState", explain: "WorkflowState n'est pas le bon objet.", }, { text: "Management", explain: "Management n'est pas un objet valide pour l'état du workflow.", } ]} /> --- ### Q3 : Quelle méthode devrait être utilisée si vous voulez qu'un agent se souvienne des interactions précédentes ? run(query_str)", explain: ".run(query_str) ne maintient pas l'historique de conversation.", }, { text: "chat(query_str, ctx=ctx)", explain: "chat() n'est pas une méthode valide sur les workflows.", }, { text: "interact(query_str)", explain: "interact() n'est pas une méthode valide pour les interactions d'agents.", }, { text: "run(query_str, ctx=ctx)", explain: "En passant et maintenant le contexte, nous pouvons maintenir l'état !", correct: true } ]} /> --- ### Q4 : Quelle est une caractéristique clé du RAG agentique ? workflow RAG", explain: "Le RAG agentique peut utiliser différents outils, incluant les outils basés sur des documents.", }, { text: "Il répond automatiquement aux questions sans outils, comme un chatbot", explain: "Le RAG agentique utilise bien des outils pour répondre aux questions.", }, { text: "Il peut décider d'utiliser n'importe quel outil pour répondre aux questions, incluant les outils RAG", explain: "Le RAG agentique a la flexibilité d'utiliser différents outils pour répondre aux questions.", correct: true }, { text: "Il ne fonctionne qu'avec les Function Calling Agents", explain: "Le RAG agentique n'est pas limité aux Function Calling Agents.", } ]} /> --- Vous avez compris ? Parfait ! Maintenant faisons **un bref récapitulatif de l'unité !** ================================================ FILE: units/fr/unit2/llama-index/tools.mdx ================================================ # Utiliser les outils dans LlamaIndex **Définir un ensemble clair d'outils est crucial pour la performance.** Comme nous l'avons discuté dans l'[Unité 1](../../unit1/tools), des interfaces claires sont plus faciles à utiliser pour les LLM. Tout comme une interface API logicielle pour les ingénieurs humains, ils peuvent tirer profit de l'outil s'il est facile de comprendre comment il fonctionne. Il y a **quatre types principaux d'outils dans LlamaIndex** : ![Tools](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/tools.png) 1. `FunctionTool` : Convertit n'importe quelle fonction Python en un outil qu'un agent peut utiliser. Il comprend automatiquement comment la fonction fonctionne. 2. `QueryEngineTool` : Un outil qui permet aux agents d'utiliser des *query engines*. Puisque les agents sont construits sur des *query engines*, ils peuvent également utiliser d'autres agents comme outil. 3. `Toolspecs` : Ensembles d'outils créés par la communauté, en incluant souvent pour des services spécifiques comme Gmail. 4. `Utility Tools` : Outils spéciaux qui aident à gérer de grandes quantités de données d'autres outils. Nous passerons en revue chacun d'eux plus en détail ci-dessous. ## Créer un *FunctionTool* > [!TIP] > Vous pouvez suivre le code dans ce notebook que vous pouvez exécuter avec Google Colab. *FunctionTool* fournit un moyen simple d'envelopper n'importe quelle fonction Python et de la rendre disponible à un agent. Vous pouvez passer soit une fonction synchrone soit asynchrone à l'outil, avec des paramètres optionnels `name` et `description`. Le nom et la description sont particulièrement importants car ils aident l'agent à comprendre quand et comment utiliser l'outil efficacement. Regardons comment créer un *FunctionTool* ci-dessous puis l'appeler. ```python from llama_index.core.tools import FunctionTool def get_weather(location: str) -> str: """Utile pour obtenir le temps qu'il fait à un endroit donné.""" print(f"Getting weather for {location}") return f"The weather in {location} is sunny" tool = FunctionTool.from_defaults( get_weather, name="my_weather_tool", description="Useful for getting the weather for a given location.", ) tool.call("New York") ``` > [!TIP] > Lors de l'utilisation d'un agent ou d'un LLM avec l'appel de fonctions, l'outil sélectionné (et les arguments écrits pour celui-ci) dépendent fortement de son nom, t de la description du but et des arguments. Apprenez-en plus sur l'appel de fonctions dans le Guide sur l'appel de fonctions. ## Créer un *QueryEngineTool* Le `QueryEngine` que nous avons défini dans l'unité précédente peut être facilement transformé en un outil en utilisant la classe `QueryEngineTool`. Voyons comment créer un `QueryEngineTool` à partir d'un `QueryEngine` dans l'exemple ci-dessous. ```python from llama_index.core import VectorStoreIndex from llama_index.core.tools import QueryEngineTool from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI from llama_index.embeddings.huggingface import HuggingFaceEmbedding from llama_index.vector_stores.chroma import ChromaVectorStore embed_model = HuggingFaceEmbedding("BAAI/bge-small-en-v1.5") db = chromadb.PersistentClient(path="./alfred_chroma_db") chroma_collection = db.get_or_create_collection("alfred") vector_store = ChromaVectorStore(chroma_collection=chroma_collection) index = VectorStoreIndex.from_vector_store(vector_store, embed_model=embed_model) llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") query_engine = index.as_query_engine(llm=llm) tool = QueryEngineTool.from_defaults(query_engine, name="some useful name", description="some useful description") ``` ## Créer un *Toolspecs* Pensez au `ToolSpecs` comme des collections d'outils qui fonctionnent ensemble harmonieusement à l'instar d'une boîte à outils professionnelle bien organisée. Tout comme la boîte à outils d'un mécanicien contient des outils complémentaires qui fonctionnent ensemble pour les réparations de véhicules, un `ToolSpec` combine des outils apparentés pour des objectifs spécifiques. Par exemple, le `ToolSpec` d'un agent comptable pourrait intégrer élégamment des capacités de tableur, des fonctionnalités email et des outils de calcul pour gérer les tâches financières avec précision et efficacité.
Installer le Toolspec Google Comme introduit dans la section sur le LlamaHub, nous pouvons installer le toolspec Google avec la commande suivante : ```python pip install llama-index-tools-google ```
Et maintenant nous pouvons charger le *toolspec* et le convertir en une liste d'outils. ```python from llama_index.tools.google import GmailToolSpec tool_spec = GmailToolSpec() tool_spec_list = tool_spec.to_tool_list() ``` Pour obtenir une vue plus détaillée des outils, nous pouvons examiner les `metadata` de chacun d'eux. ```python [(tool.metadata.name, tool.metadata.description) for tool in tool_spec_list] ``` ### *Model Context Protocol* (MCP) dans LlamaIndex LlamaIndex permet également d'utiliser les outils *MCP* grâce à un [*ToolSpec* sur le LlamaHub](https://llamahub.ai/l/tools/llama-index-tools-mcp?from=). Vous pouvez simplement lancer un serveur MCP et commencer à l'utiliser grâce à l'implémentation suivante. Si vous voulez approfondir MCP, vous pouvez consulter notre [cours gratuit](https://huggingface.co/learn/mcp-course/).
Installer le Toolspec MCP Comme introduit dans la section sur le LlamaHub, nous pouvons installer le toolspec MCP avec la commande suivante : ```python pip install llama-index-tools-mcp ```
```python from llama_index.tools.mcp import BasicMCPClient, McpToolSpec # Nous considérons qu'un serveur mcp tourne sur 127.0.0.1:8000, ou vous pouvez utiliser le client mcp pour vous connecter à votre propre serveur mcp_client = BasicMCPClient("http://127.0.0.1:8000/sse") mcp_tool = McpToolSpec(client=mcp_client) # obtenir l'agent agent = await get_agent(mcp_tool) # créer le contexte de l'agent agent_context = Context(agent) ``` ## *Utility Tools* Souvent, interroger directement une API **peut retourner une quantité excessive de données**, dont certaines peuvent être non pertinentes, déborder la fenêtre de contexte du LLM, ou augmenter inutilement le nombre de *tokens* que vous utilisez. Passons en revue nos deux *utility tools* principaux ci-dessous. 1. `OnDemandToolLoader` : Cet outil transforme n'importe quel chargeur de données LlamaIndex existant (classe *BaseReader*) en un outil qu'un agent peut utiliser. Il peut être appelé avec tous les paramètres nécessaires pour déclencher `load_data` du chargeur de données, ainsi qu'une chaîne de requête en langage naturel. Pendant l'exécution, nous chargeons d'abord les données du chargeur de données, les indexons (par exemple avec un *vector store*), puis les interrogeons à la demande. Ces trois étapes se produisent dans un seul appel de l'outil. 2. `LoadAndSearchToolSpec` : Le *LoadAndSearchToolSpec* prend n'importe quel outil existant en entrée. En tant que *tool spec*, il implémente `to_tool_list`, et quand cette fonction est appelée, deux outils sont retournés : un outil de chargement puis un outil de recherche. L'exécution du premier appellerait l'outil sous-jacent, puis indexerait la sortie (par défaut avec un *vector index*). L'exécution du second prendrait une chaîne de requête en entrée et appellerait l'index sous-jacent. > [!TIP] > Vous pouvez trouver des toolspecs et des utility tools sur le LlamaHub. Maintenant que nous comprenons les bases des agents et des outils dans LlamaIndex, voyons comment nous pouvons **utiliser LlamaIndex pour créer des *workflows* configurables et gérables !** ================================================ FILE: units/fr/unit2/llama-index/workflows.mdx ================================================ # Créer des *workflows* agentiques dans LlamaIndex Un *workflow* dans LlamaIndex fournit un moyen structuré d'organiser votre code en étapes séquentielles et gérables. Un tel *workflow* est créé en définissant des `Steps` qui sont déclenchés par des `Events`, et qui émettent eux-mêmes des `Events` pour déclencher d'autres étapes. Jetons un coup d'œil à Alfred montrant un *workflow* LlamaIndex pour une tâche de RAG. ![Workflow Schematic](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/workflows.png) **Les *workflows* offrent plusieurs avantages clés :** - Organisation claire du code en étapes discrètes - Architecture événementielle pour un flux de contrôle flexible - Communication *type-safe* entre les étapes - Gestion d'état intégrée - Support pour des interactions d'agents simples et complexes Comme vous l'avez peut-être deviné, **les *workflows* trouvent un excellent équilibre entre l'autonomie des agents tout en maintenant le contrôle sur le *workflow* global.** Alors, apprenons à créer un *workflow* nous-mêmes ! ## Créer des *Workflows* > [!TIP] > Vous pouvez suivre le code dans ce notebook que vous pouvez exécuter avec Google Colab. ### Création de *Workflow* de base
Installer le package Workflow Comme introduit dans la section sur le LlamaHub, nous pouvons installer le package Workflow avec la commande suivante : ```python pip install llama-index-utils-workflow ```
Nous pouvons créer un *workflow* en une seule étape en définissant une classe qui hérite de `Workflow` et en décorant vos fonctions avec `@step`. Nous devrons également ajouter `StartEvent` et `StopEvent`, qui sont des événements spéciaux utilisés pour indiquer le début et la fin du *workflow*. ```python from llama_index.core.workflow import StartEvent, StopEvent, Workflow, step class MyWorkflow(Workflow): @step async def my_step(self, ev: StartEvent) -> StopEvent: # do something here return StopEvent(result="Hello, world!") w = MyWorkflow(timeout=10, verbose=False) result = await w.run() ``` Comme vous pouvez le voir, nous pouvons maintenant exécuter le *workflow* en appelant `w.run()`. ### Connecter plusieurs étapes Pour connecter plusieurs étapes, nous **créons des événements personnalisés qui transportent des données entre les étapes.** Pour ce faire, nous devons ajouter un `Event` qui est passé entre les étapes et transfère la sortie de la première étape vers la deuxième étape. ```python from llama_index.core.workflow import Event class ProcessingEvent(Event): intermediate_result: str class MultiStepWorkflow(Workflow): @step async def step_one(self, ev: StartEvent) -> ProcessingEvent: # Traitement des données initiales return ProcessingEvent(intermediate_result="Step 1 complete") @step async def step_two(self, ev: ProcessingEvent) -> StopEvent: # Utiliser le résultat intermédiaire final_result = f"Finished processing: {ev.intermediate_result}" return StopEvent(result=final_result) w = MultiStepWorkflow(timeout=10, verbose=False) result = await w.run() result ``` L'indication de type est importante ici, car elle garantit que le *workflow* est exécuté correctement. Compliquons un peu les choses ! ### Boucles et branches L'indication de type est la partie la plus puissante des *workflows* car elle nous permet de créer des branches, des boucles et des jointures pour faciliter des *workflows* plus complexes. Montrons un exemple de **création d'une boucle** en utilisant l'opérateur union `|`. Dans l'exemple ci-dessous, nous voyons que le `LoopEvent` est pris en entrée pour l'étape et peut également être retourné en sortie. ```python from llama_index.core.workflow import Event import random class ProcessingEvent(Event): intermediate_result: str class LoopEvent(Event): loop_output: str class MultiStepWorkflow(Workflow): @step async def step_one(self, ev: StartEvent | LoopEvent) -> ProcessingEvent | LoopEvent: if random.randint(0, 1) == 0: print("Bad thing happened") return LoopEvent(loop_output="Back to step one.") else: print("Good thing happened") return ProcessingEvent(intermediate_result="First step complete.") @step async def step_two(self, ev: ProcessingEvent) -> StopEvent: # Utiliser le résultat intermédiaire final_result = f"Finished processing: {ev.intermediate_result}" return StopEvent(result=final_result) w = MultiStepWorkflow(verbose=False) result = await w.run() result ``` ### Dessiner des *Workflows* Nous pouvons également dessiner des *workflows*. Utilisons la fonction `draw_all_possible_flows` pour dessiner le *workflow*. Cela stocke le *workflow* dans un fichier HTML. ```python from llama_index.utils.workflow import draw_all_possible_flows w = ... # tel que défini dans la section précédentetel que défini dans la section précédente draw_all_possible_flows(w, "flow.html") ``` ![workflow drawing](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/workflow-draw.png) Il y a une dernière astuce cool que nous couvrirons dans le cours, qui est la capacité d'ajouter de l'état au *workflow*. ### Gestion d'état La gestion d'état est utile quand vous voulez garder une trace de l'état du *workflow*, pour que chaque étape ait accès au même état. Nous pouvons faire cela en utilisant l'indication de type `Context` au-dessus d'un paramètre dans la fonction d'étape. ```python from llama_index.core.workflow import Context, StartEvent, StopEvent @step async def query(self, ctx: Context, ev: StartEvent) -> StopEvent: # stocker la requête dans le contexte await ctx.store.set("query", "What is the capital of France?") # faire quelque chose avec le contexte et l'event val = ... # récupérer la requête dans le contexte query = await ctx.store.get("query") return StopEvent(result=val) ``` Parfait ! Maintenant vous savez comment créer des *workflows* de base dans LlamaIndex ! > [!TIP] > Il y a quelques nuances plus complexes aux workflows, que vous pouvez apprendre dans la documentation LlamaIndex. Cependant, il y a une autre façon de créer des *workflows*, qui repose sur la classe `AgentWorkflow`. Jetons un coup d'œil à comment nous pouvons utiliser cela pour créer un *workflow* multi-agents. ## Automatiser les *workflows* avec des *Multi-Agent Workflows* Au lieu de la création manuelle de *workflows*, nous pouvons utiliser la **classe `AgentWorkflow` pour créer un *workflow* multi-agents**. L'`AgentWorkflow` utilise des *Workflow Agents* pour vous permettre de créer un système d'un ou plusieurs agents qui peuvent collaborer et se passer des tâches entre eux basées sur leurs capacités spécialisées. Cela permet de construire des systèmes d'agents complexes où différents agents gèrent différents aspects d'une tâche. Au lieu d'importer des classes de `llama_index.core.agent`, nous importerons les classes d'agents de `llama_index.core.agent.workflow`. Un agent doit être désigné comme l'agent racine dans le constructeur `AgentWorkflow`. Quand un message utilisateur arrive, il est d'abord routé vers l'agent racine. Chaque agent peut ensuite : - Gérer la demande directement en utilisant leurs outils - Passer le relais à un autre agent mieux adapté à la tâche - Retourner une réponse à l'utilisateur Voyons comment créer un *workflow* multi-agents. ```python from llama_index.core.agent.workflow import AgentWorkflow, ReActAgent from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI # Définir quelques outils def add(a: int, b: int) -> int: """Additionner deux nombres.""" return a + b def multiply(a: int, b: int) -> int: """Multiplier deux nombres.""" return a * b llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") # nous pouvons passer des fonctions directement sans FunctionTool -- les fn/docstring sont analysés pour le nom/description multiply_agent = ReActAgent( name="multiply_agent", description="Is able to multiply two integers", system_prompt="A helpful assistant that can use a tool to multiply numbers.", tools=[multiply], llm=llm, ) addition_agent = ReActAgent( name="add_agent", description="Is able to add two integers", system_prompt="A helpful assistant that can use a tool to add numbers.", tools=[add], llm=llm, ) # Créer le workflow workflow = AgentWorkflow( agents=[multiply_agent, addition_agent], root_agent="multiply_agent", ) # Exécuter le système response = await workflow.run(user_msg="Can you add 5 and 3?") ``` Les outils d'agents peuvent également modifier l'état du *workflow* que nous avons mentionné plus tôt. Avant de commencer le *workflow*, nous pouvons fournir un dictionnaire d'état initial qui sera disponible pour tous les agents. L'état est stocké dans la clé d'état du contexte du *workflow*. Il sera injecté dans le *state_prompt* qui augmente chaque nouveau message utilisateur. Injectons un compteur pour compter les appels de fonctions en modifiant l'exemple précédent : ```python from llama_index.core.workflow import Context # Définir quelques outils async def add(ctx: Context, a: int, b: int) -> int: """Additionner deux nombres.""" # mettre à jour notre comptage cur_state = await ctx.store.get("state") cur_state["num_fn_calls"] += 1 await ctx.store.set("state", cur_state) return a + b async def multiply(ctx: Context, a: int, b: int) -> int: """Multiplier deux nombres.""" # mettre à jour notre comptage cur_state = await ctx.store.get("state") cur_state["num_fn_calls"] += 1 await ctx.store.set("state", cur_state) return a * b ... workflow = AgentWorkflow( agents=[multiply_agent, addition_agent], root_agent="multiply_agent", initial_state={"num_fn_calls": 0}, state_prompt="Current state: {state}. User message: {msg}", ) # exécuter le workflow avec le contexte ctx = Context(workflow) response = await workflow.run(user_msg="Can you add 5 and 3?", ctx=ctx) # sortir et inspecter l'état state = await ctx.store.get("state") print(state["num_fn_calls"]) ``` Félicitations ! Vous avez maintenant passer en revue les bases des agents dans LlamaIndex ! 🎉 Continuons avec un dernier quiz pour solidifier vos connaissances ! 🚀 ================================================ FILE: units/fr/unit2/smolagents/code_agents.mdx ================================================ # Construire des agents qui utilisent du code Les agents à code sont le type d'agent par défaut dans `smolagents`. Ils génèrent des appels d'outils Python pour effectuer des actions, obtenant des représentations d'actions qui sont efficaces, expressives et précises. Leur approche simplifiée réduit le nombre d'actions requises, simplifie les opérations complexes et permet la réutilisation de fonctions de code existantes. `smolagents` fournit un *framework* léger pour construire de tels agents en environ 1 000 lignes de code. ![Code vs JSON Actions](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/code_vs_json_actions.png) Graphique issu du papier [Executable Code Actions Elicit Better LLM Agents](https://huggingface.co/papers/2402.01030) > [!TIP] > Si vous voulez en savoir plus sur pourquoi les agents à code sont efficaces, consultez ce guide de la documentation smolagents. ## Pourquoi les agents à code ? Dans un processus d'agent multi-étapes, le LLM écrit et exécute des actions, impliquant généralement des appels d'outils externes. Les approches traditionnelles utilisent un format JSON pour spécifier les noms d'outils et les arguments sous forme de chaînes, **que le système doit analyser pour déterminer quel outil exécuter**. Cependant, la recherche montre que **les LLM d'appel d'outils fonctionnent plus efficacement avec du code directement**. C'est un principe fondamental de `smolagents`, comme le montre le diagramme ci-dessus issu de [*Executable Code Actions Elicit Better LLM Agents*](https://huggingface.co/papers/2402.01030). Écrire des actions en code plutôt qu'en JSON offre plusieurs avantages clés : * **Composabilité** : Combiner et réutiliser facilement des actions * **Gestion d'objets** : Travailler directement avec des structures complexes comme des images * **Généralité** : Exprimer toute tâche computationnellement possible * **Naturel pour les LLM** : Du code de haute qualité est déjà présent dans les données d'entraînement des LLM ## Comment fonctionne un agent à code ? ![From https://huggingface.co/docs/smolagents/conceptual_guides/react](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/smolagents/codeagent_docs.png) Le diagramme ci-dessus illustre comment `CodeAgent.run()` fonctionne, suivant le *framework* ReAct que nous avons mentionné dans l'Unité 1. L'abstraction principale pour les agents dans `smolagents` est un `MultiStepAgent` qui sert de bloc de construction principal. Comme nous le verrons dans un exemple ci-dessous, `CodeAgent` est un type spécial de `MultiStepAgent`. Un `CodeAgent` effectue des actions à travers un cycle d'étapes (avec les variables existantes et les connaissances étant incorporées dans le contexte de l'agent) qui est conservé dans un journal d'exécution : 1. Le *prompt* système est stocké dans un `SystemPromptStep` et la requête utilisateur est enregistrée dans un `TaskStep`. 2. Ensuite, la boucle *while* suivante est exécutée : 2.1 La méthode `agent.write_memory_to_messages()` écrit les *logs* de l'agent dans une liste de [messages de chat](https://huggingface.co/docs/transformers/main/en/chat_templating) lisibles par le LLM. 2.2 Ces messages sont envoyés à un `Model` qui génère une complétion. 2.3 La complétion est analysée pour extraire l'action, qui, dans notre cas, devrait être un extrait de code puisque nous travaillons avec un `CodeAgent`. 2.4 L'action est exécutée. 2.5 Les résultats sont enregistrés en mémoire dans un `ActionStep`. À la fin de chaque étape, si l'agent inclut des appels de fonction (dans `agent.step_callback`), ils sont exécutés. ## Voyons quelques exemples > [!TIP] > Vous pouvez suivre le code dans ce notebook que vous pouvez exécuter avec Google Colab. Alfred planifie une fête au manoir de la famille Wayne et a besoin de votre aide pour s'assurer que tout se passe bien. Pour l'aider, nous appliquerons ce que nous avons appris sur le fonctionnement d'un `CodeAgent` multi-étapes. Alfred Party Si vous n'avez pas encore installé `smolagents`, vous pouvez le faire en exécutant la commande suivante : ```bash pip install smolagents -U ``` Connectons-nous également au Hub d'Hugging Face pour avoir accès à l'API d'inférence *Serverless*. ```python from huggingface_hub import login login() ``` ### Sélectionner une *playlist* pour la fête en utilisant `smolagents` La musique est un élément essentiel d'une fête réussie ! Alfred a besoin d'aide pour sélectionner la *playlist*. Heureusement, `smolagents` nous couvre ! Nous pouvons construire un agent capable de rechercher sur le web en utilisant DuckDuckGo. Pour donner à l'accès à cet outil l'agent, nous l'incluons dans la liste des outils lors de la création de l'agent. Alfred Playlist Pour le modèle, nous nous appuierons sur `InferenceClientModel`, qui fournit l'accès à l'[API d'inférence Serverless](https://huggingface.co/docs/api-inference/index) d'Hugging Face. Le modèle par défaut est `"Qwen/Qwen2.5-Coder-32B-Instruct"`, qui est performant et disponible pour une inférence rapide, mais vous pouvez sélectionner depuis le Hub n'importe quel modèle compatible. Exécuter un agent est assez simple : ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel agent = CodeAgent(tools=[DuckDuckGoSearchTool()], model=InferenceClientModel()) agent.run("Recherche les meilleures recommandations musicales pour une fête au manoir des Wayne.") ``` Lorsque vous exécutez cet exemple, la sortie **affichera une trace des étapes du *workflow* en cours d'exécution**. Elle affichera également le code Python correspondant avec le message : ```python ─ Executing parsed code: ──────────────────────────────────────────────────────────────────────────────────────── results = web_search(query="best music for a Batman party") print(results) ───────────────────────────────────────────────────────────────────────────────────────────────────────────────── ``` Après quelques étapes, vous verrez la *playlist* générée qu'Alfred peut utiliser pour la fête ! 🎵 ### Utiliser un outil personnalisé pour préparer le menu Alfred Menu Maintenant que nous avons sélectionné une *playlist*, nous devons organiser le menu pour les invités. Encore une fois, Alfred peut tirer parti de `smolagents` pour le faire. Ici, nous utilisons le décorateur `@tool` pour définir une fonction personnalisée qui agit comme un outil. Nous couvrirons la création d'outils plus en détail plus tard, donc pour l'instant, nous pouvons simplement exécuter le code. Comme vous pouvez le voir dans l'exemple ci-dessous, nous allons créer un outil en utilisant le décorateur `@tool` et l'inclure dans la liste `tools`. ```python from smolagents import CodeAgent, tool, InferenceClientModel # Outil pour suggérer un menu basé sur l'occasion @tool def suggest_menu(occasion: str) -> str: """ Suggère un menu basé sur l'occasion. Args: occasion (str): Le type d'occasion pour la fête. Les valeurs autorisées sont : - "casual": Menu pour une fête décontractée. - "formal": Menu pour une fête formelle. - "superhero": Menu pour une fête de super-héros. - "custom": Menu personnalisé. """ if occasion == "casual": return "Pizza, collations et boissons." elif occasion == "formal": return "Dîner 3 services avec vin et dessert." elif occasion == "superhero": return "Buffet avec nourriture énergétique et saine." else: return "Menu personnalisé pour le majordome." # Alfred, le majordome, préparant le menu pour la fête agent = CodeAgent(tools=[suggest_menu], model=InferenceClientModel()) # Préparer le menu pour la fête agent.run("Prépare un menu formel pour la fête.") ``` L'agent s'exécutera pendant quelques étapes jusqu'à trouver la réponse. Préciser les valeurs autorisées dans la docstring aide à diriger l'agent vers les valeurs d'argument `occasion` qui existent et limite les hallucinations. Le menu est prêt ! 🥗 ### Utiliser des imports Python à l'intérieur de l'agent Nous avons la *playlist* et le menu prêts, mais nous devons vérifier un dernier détail crucial : le temps de préparation ! Alfred doit calculer quand tout serait prêt s'il commençait à préparer maintenant, au cas où ils auraient besoin de l'aide d'autres super-héros. `smolagents` est spécialisé dans les agents qui écrivent et exécutent des extraits de code Python, offrant une exécution sécurisée. En effet, **l'exécution du code a des mesures de sécurité strictes** : les imports en dehors d'une liste sûre prédéfinie sont bloqués par défaut. Cependant, vous pouvez autoriser des imports supplémentaires en les passant sous forme de chaînes dans `additional_authorized_imports`. Pour plus de détails sur l'exécution sécurisée du code, consultez le [guide](https://huggingface.co/docs/smolagents/tutorials/secure_code_execution) officiel. Lors de la création de l'agent, nous utiliserons `additional_authorized_imports` pour permettre l'importation du module `datetime`. ```python from smolagents import CodeAgent, InferenceClientModel import numpy as np import time import datetime agent = CodeAgent(tools=[], model=InferenceClientModel(), additional_authorized_imports=['datetime']) agent.run( """ Alfred doit se préparer pour la fête. Voici les tâches : 1. Préparer les boissons - 30 minutes 2. Décorer le manoir - 60 minutes 3. Mettre en place le menu - 45 minutes 4. Préparer la musique et la playlist - 45 minutes Si nous commençons maintenant, à quelle heure la fête sera-t-elle prête ? """ ) ``` Ces exemples ne sont que le début de ce que vous pouvez faire avec les agents à code, et nous commençons déjà à voir leur utilité pour préparer la fête. Vous pouvez en apprendre davantage sur la façon de construire de tels agents dans la [documentation de `smolagents`](https://huggingface.co/docs/smolagents). En résumé, `smolagents` se spécialise dans les agents qui écrivent et exécutent des extraits de code Python, offrant une exécution sécurisée. Il supporte à la fois les modèles de langage locaux et basés sur API, le rendant adaptable à divers environnements de développement. ### Partager notre agent préparateur de fête personnalisé sur le Hub Ne serait-il pas **incroyable de partager notre propre agent Alfred avec le reste du monde** ? En faisant cela, n'importe qui peut facilement télécharger et utiliser l'agent directement depuis le Hub, apportant l'ultime planificateur de fête de Gotham à portée de main ! Faisons-le ! 🎉 La bibliothèque `smolagents` rend cela possible en vous permettant de partager un agent complet avec la communauté et de télécharger ceux des autres pour une utilisation immédiate. C'est aussi simple que ce qui suit : ```python # Changez pour votre nom d'utilisateur et nom de dépôt agent.push_to_hub('sergiopaniego/AlfredAgent') ``` Pour télécharger à nouveau l'agent, utilisez le code ci-dessous : ```python # Changez pour votre nom d'utilisateur et nom de dépôt alfred_agent = agent.from_hub('sergiopaniego/AlfredAgent', trust_remote_code=True) alfred_agent.run("Donne-moi la meilleure playlist pour une fête au manoir des Wayne. L'idée de la fête est un thème 'mascarade de méchants'") ``` Ce qui est également excitant, c'est que les agents partagés sont directement disponibles en tant que *Spaces*, vous permettant d'interagir avec eux en temps réel. Vous pouvez explorer d'autres agents [ici](https://huggingface.co/spaces/davidberenstein1957/smolagents-and-tools). Par exemple, l'_AlfredAgent_ est disponible [ici](https://huggingface.co/spaces/sergiopaniego/AlfredAgent). Vous pouvez l'essayer directement ci-dessous : Vous vous demandez peut-être comment Alfred a construit un tel agent en utilisant `smolagents` ? En intégrant plusieurs outils, il peut générer un agent comme suit. Ne vous inquiétez pas des outils pour l'instant, car nous aurons une section dédiée plus tard dans cette unité pour explorer cela en détail : ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, FinalAnswerTool, InferenceClientModel, Tool, tool, VisitWebpageTool @tool def suggest_menu(occasion: str) -> str: """ Suggère un menu basé sur l'occasion. Args: occasion: Le type d'occasion pour la fête. """ if occasion == "casual": return "Pizza, collations et boissons." elif occasion == "formal": return "Dîner 3 services avec vin et dessert." elif occasion == "superhero": return "Buffet avec nourriture énergétique et saine." else: return "Menu personnalisé pour le majordome." @tool def catering_service_tool(query: str) -> str: """ Cet outil renvoie le service de restauration le mieux noté à Gotham City. Args: query: Un terme de recherche pour trouver des services de restauration. """ # Exemple de liste de services de restauration et leurs notes services = { "Gotham Catering Co.": 4.9, "Wayne Manor Catering": 4.8, "Gotham City Events": 4.7, } # Trouver le service de restauration le mieux noté (simuler le filtrage de requête de recherche) best_service = max(services, key=services.get) return best_service class SuperheroPartyThemeTool(Tool): name = "superhero_party_theme_generator" description = """ Cet outil suggère des idées créatives de fête sur le thème des super-héros basées sur une catégorie. Il renvoie une idée de thème de fête unique.""" inputs = { "category": { "type": "string", "description": "Le type de fête de super-héros (par ex., 'héros classiques', 'mascarade de méchants', 'Gotham futuriste').", } } output_type = "string" def forward(self, category: str): themes = { "classic heroes": "Gala de la Justice League : Les invités viennent habillés comme leurs héros DC préférés avec des cocktails thématiques comme 'Le Punch Kryptonite'.", "villain masquerade": "Bal des Voyous de Gotham : Une mascarade mystérieuse où les invités s'habillent en méchants classiques de Batman.", "futuristic Gotham": "Nuit Neo-Gotham : Une fête de style cyberpunk inspirée de Batman Beyond, avec des décorations néon et des gadgets futuristes." } return themes.get(category.lower(), "Idée de fête thématique non trouvée. Essayez 'héros classiques', 'mascarade de méchants', ou 'Gotham futuriste'.") # Alfred, le majordome, préparant le menu pour la fête agent = CodeAgent( tools=[ DuckDuckGoSearchTool(), VisitWebpageTool(), suggest_menu, catering_service_tool, SuperheroPartyThemeTool(), FinalAnswerTool() ], model=InferenceClientModel(), max_steps=10, verbosity_level=2 ) agent.run("Donne-moi la meilleure playlist pour une fête au manoir des Wayne. L'idée de la fête est un thème 'mascarade de méchants'") ``` Comme vous pouvez le voir, nous avons créé un `CodeAgent` avec plusieurs outils qui améliorent la fonctionnalité de l'agent, le transformant en l'ultime planificateur de fête prêt à partager avec la communauté ! 🎉 Maintenant, c'est à votre tour : construisez votre propre agent et partagez-le avec la communauté en utilisant les connaissances que nous venons d'apprendre ! 🕵️‍♂️💡 > [!TIP] > Si vous souhaitez partager votre projet d'agent, créez un Space et taguez agents-course sur le Hub. Nous serions ravis de voir ce que vous avez créé ! ### Inspecter notre agent préparateur de fête avec OpenTelemetry et Langfuse 📡 Alors qu'Alfred peaufine l'agent, il se lasse de déboguer ses exécutions. Les agents, par nature, sont imprévisibles et difficiles à inspecter. Mais comme il vise à construire l'ultime agent préparateur de fête et à le déployer en production, il a besoin d'une traçabilité robuste pour la surveillance et l'analyse futures. Encore une fois, `smolagents` vient à la rescousse ! Il adopte la norme [OpenTelemetry](https://opentelemetry.io/) pour instrumenter les exécutions d'agents, permettant une inspection et une journalisation transparentes. Avec l'aide de [Langfuse](https://langfuse.com/) et du `SmolagentsInstrumentor`, Alfred peut facilement suivre et analyser le comportement de son agent. La configuration est simple ! D'abord, nous devons installer les dépendances nécessaires : ```bash pip install opentelemetry-sdk opentelemetry-exporter-otlp openinference-instrumentation-smolagents langfuse ``` Ensuite, Alfred a déjà créé un compte sur Langfuse et a ses clés API prêtes. Si vous ne l'avez pas encore fait, vous pouvez vous inscrire à Langfuse Cloud [ici](https://cloud.langfuse.com/) ou explorer des [alternatives](https://huggingface.co/docs/smolagents/tutorials/inspect_runs). Une fois que vous avez vos clés API, elles doivent être correctement configurées comme suit : ```python import os # Obtenez les clés pour votre projet depuis la page des paramètres du projet : https://cloud.langfuse.com os.environ["LANGFUSE_PUBLIC_KEY"] = "pk-lf-..." os.environ["LANGFUSE_SECRET_KEY"] = "sk-lf-..." os.environ["LANGFUSE_HOST"] = "https://cloud.langfuse.com" # 🇪🇺 Région UE # os.environ["LANGFUSE_HOST"] = "https://us.cloud.langfuse.com" # 🇺🇸 Région US ``` Avec les variables d'environnement définies, nous pouvons maintenant initialiser le client Langfuse. `get_client()` initialise le client Langfuse en utilisant les identifiants fournis dans les variables d'environnement. ```python from langfuse import get_client langfuse = get_client() # Vérifier la connexion if langfuse.auth_check(): print("Le client Langfuse est authentifié et prêt !") else: print("L'authentification a échoué. Veuillez vérifier vos identifiants et l'hôte.") ``` Enfin, Alfred est prêt à initialiser le `SmolagentsInstrumentor` et commencer à suivre les performances de son agent. ```python from openinference.instrumentation.smolagents import SmolagentsInstrumentor SmolagentsInstrumentor().instrument() ``` Alfred est maintenant connecté 🔌 ! Les exécutions de `smolagents` sont enregistrées dans Langfuse, lui donnant une visibilité complète sur le comportement de l'agent. Avec cette configuration, il est prêt à revisiter les exécutions précédentes et à affiner encore plus son agent préparateur de fête. > [!TIP] > Pour en savoir plus sur le traçage de vos agents et l'utilisation des données collectées pour évaluer leurs performances, consultez l'Unité Bonus 2. ```python from smolagents import CodeAgent, InferenceClientModel agent = CodeAgent(tools=[], model=InferenceClientModel()) alfred_agent = agent.from_hub('sergiopaniego/AlfredAgent', trust_remote_code=True) alfred_agent.run("Donne-moi la meilleure playlist pour une fête au manoir des Wayne. L'idée de la fête est un thème 'mascarade de méchants'") ``` Alfred peut maintenant accéder aux logs [ici](https://cloud.langfuse.com/project/cm7bq0abj025rad078ak3luwi/traces/995fc019255528e4f48cf6770b0ce27b?timestamp=2025-02-19T10%3A28%3A36.929Z) pour les relire et les analyser. > [!TIP] > En fait, une erreur mineure s'est produite lors de l'exécution. Pouvez-vous la repérer dans les logs ? Essayez de suivre comment l'agent la gère et renvoie quand même une réponse valide. Voici le lien direct vers l'erreur si vous voulez vérifier votre réponse. Bien sûr, l'erreur a été corrigée entre-temps, plus de détails peuvent être trouvés dans cette issue. Pendant ce temps, la [*playlist* suggérée](https://open.spotify.com/playlist/0gZMMHjuxMrrybQ7wTMTpw) crée l'ambiance parfaite pour les préparatifs de la fête. Cool, non ? 🎶 --- Maintenant que nous avons créé notre premier *Code Agent*, **apprenons comment nous pouvons créer des *Tool Calling Agents***, le deuxième type d'agent disponible dans `smolagents`. ## Ressources - [Blog smolagents](https://huggingface.co/blog/smolagents) - Introduction à smolagents et aux interactions de code - [smolagents : Construire de bons agents](https://huggingface.co/docs/smolagents/tutorials/building_good_agents) - Meilleures pratiques pour des agents fiables - [Construire des agents efficaces - Anthropic](https://www.anthropic.com/research/building-effective-agents) - Principes de conception d'agents - [Partager des exécutions avec OpenTelemetry](https://huggingface.co/docs/smolagents/tutorials/inspect_runs) - Détails sur la façon de configurer OpenTelemetry pour suivre vos agents. ================================================ FILE: units/fr/unit2/smolagents/conclusion.mdx ================================================ # Conclusion Félicitations d'avoir terminé le module `smolagents` de cette deuxième unité 🥳 Vous **maîtrisez les fondamentaux** de `smolagents` et vous avez construit votre propre agent ! A présent que vous avez des compétences sur `smolagents`, vous pouvez maintenant commencer à créer des agents qui résoudront des tâches qui vous intéressent. Dans le prochain module, vous allez apprendre **comment construire des agents avec LlamaIndex**. Enfin, nous serions ravis **d'entendre ce que vous pensez du cours et comment nous pourrions l'améliorer**. Si vous avez des retours, n'hésitez pas à [remplir ce formulaire](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog). ### Continuez à apprendre, restez géniaux 🤗 ================================================ FILE: units/fr/unit2/smolagents/final_quiz.mdx ================================================ # C'est l'heure de l'examen ! Bravo d'avoir suivi sur le matériel sur `smolagents` ! Vous en avez déjà fait beaucoup. Maintenant, il est temps de mettre vos connaissances à l'épreuve avec un quiz. 🧠 ## Instructions - Le quiz consiste en des questions de code. - Vous recevrez des instructions pour compléter les extraits de code. - Lisez attentivement les instructions et complétez les extraits de code en conséquence. - Pour chaque question, vous recevrez le résultat et quelques commentaires. 🧘 **Ce quiz n'est pas noté et non certifié**. Il s'agit de vous faire comprendre la bibliothèque `smolagents` et de savoir si vous devriez passer plus de temps sur le matériel écrit. Dans les unités à venir, vous mettrez ces connaissances à l'épreuve dans des cas d'usage et des projets. Commençons ! ## Quiz 🚀 Vous pouvez également accéder au quiz 👉 [ici](https://huggingface.co/spaces/agents-course/unit2_smolagents_quiz) ================================================ FILE: units/fr/unit2/smolagents/introduction.mdx ================================================ # Introduction à `smolagents` Unit 2.1 Thumbnail Bienvenue dans ce module, où vous allez apprendre **comment construire des agents efficaces** en utilisant la bibliothèque [`smolagents`](https://github.com/huggingface/smolagents), qui fournit un *framework* léger pour en créer des performants. `smolagents` est une bibliothèque d'Hugging Face ; par conséquent, nous apprécierions votre soutien en **mettant une étoile** au [`dépôt GitHub`](https://github.com/huggingface/smolagents) : staring smolagents ## Vue d'ensemble du module Ce module offre une vue d'ensemble complète des concepts clés et des stratégies pratiques pour construire des agents intelligents en utilisant `smolagents`. Avec tant de *frameworks open-source* disponibles, il est essentiel de comprendre les composants et les capacités qui font de `smolagents` une option utile ou de déterminer quand une autre solution pourrait être un meilleur choix. Nous explorerons des types d'agents critiques, y compris les agents à code conçus pour les tâches de développement logiciel, les agents d'appel d'outils pour créer des *workflows* modulaires basés sur des fonctions, et les agents de récupération qui accèdent et synthétisent l'information. De plus, nous couvrirons l'orchestration de plusieurs agents ainsi que l'intégration des capacités de vision et de navigation web, qui débloquent de nouvelles possibilités pour des applications dynamiques et contextuelles. Dans cette unité, Alfred, l'agent de l'unité 1, fait son retour. Cette fois, il utilise `smolagents` pour son fonctionnement interne. Ensemble, nous explorerons les concepts clés derrière ce *framework* pendant qu'Alfred s'attaquera à diverses tâches. Alfred organise une fête au manoir Wayne pendant que la famille Wayne 🦇 est absente, et il a beaucoup à faire. Rejoignez-nous pour découvrir son parcours et comment il gère ces tâches avec `smolagents` ! > [!TIP] > Dans cette unité, vous apprendrez à construire des agents avec la bibliothèque `smolagents`. Vos agents pourront rechercher des données, exécuter du code et interagir avec des pages web. Vous apprendrez également comment combiner plusieurs agents pour créer des systèmes plus puissants. ![Alfred the agent](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit1/this-is-alfred.jpg) ## Contenu Lors de cette unité nous allons couvir : ### 1️⃣ [Pourquoi utiliser smolagents](./why_use_smolagents) `smolagents` est l'un des nombreux *frameworks* d'agents *open-source* disponibles pour le développement d'applications. Les options alternatives incluent `LlamaIndex` et `LangGraph`, qui sont également couverts dans d'autres modules de ce cours. `smolagents` offre plusieurs fonctionnalités clés qui pourraient en faire un excellent choix pour des cas d'usage spécifiques, mais nous devons toujours considérer toutes les options lors de la sélection d'un *framework*. Nous explorerons les avantages et les inconvénients de l'utilisation de `smolagents`, vous aidant à prendre une décision éclairée basée sur les exigences de votre projet. ### 2️⃣ [CodeAgents](./code_agents) Les `CodeAgents` sont le type principal d'agent dans `smolagents`. Au lieu de générer du *JSON* ou du texte, ces agents produisent du code Python pour effectuer des actions. Ce module explore leur objectif, leur fonctionnalité et leur fonctionnement, avec des exemples pratiques pour présenter leurs capacités. ### 3️⃣ [ToolCallingAgents](./tool_calling_agents) Les `ToolCallingAgents` sont le deuxième type d'agent pris en charge par `smolagents`. Contrairement aux `CodeAgents`, qui génèrent du code Python, ces agents s'appuient sur des blobs *JSON*/texte que le système doit analyser et interpréter pour exécuter des actions. Ce module couvre leur fonctionnalité, leurs principales différences avec les `CodeAgents`, et fournit un exemple pour illustrer leur utilisation. ### 4️⃣ [Outils](./tools) Comme nous l'avons vu dans l'unité 1, les outils sont des fonctions qu'un *LLM* peut utiliser dans un système agentique. Is agissent comme les blocs de construction essentiels pour le comportement de l'agent. Ce module couvre comment créer des outils, leur structure et différentes méthodes d'implémentation utilisant la classe `Tool` ou le décorateur `@tool`. Vous en saurez également plus sur la boîte à outils par défaut, ainsi que sur comment partager des outils avec la communauté ou encore comment charger des outils créés par la communauté pour les utiliser dans vos agents. ### 5️⃣ [Agents de récupération](./retrieval_agents) Les agents de récupération permettent aux modèles d'accéder aux bases de connaissances, rendant possible la recherche, la synthèse et la récupération d'informations à partir de plusieurs sources. Ils exploitent des bases vectorielles pour une récupération efficace et implémentent des modèles de ***Retrieval-Augmented Generation* (*RAG*)**. Ces agents sont particulièrement utiles pour intégrer la recherche web avec des bases de connaissances personnalisées tout en maintenant le contexte de conversation à travers des systèmes de mémoire. Ce module explore les stratégies d'implémentation, y compris les mécanismes de repli pour une récupération d'information robuste. ### 6️⃣ [Systèmes multi-agents](./multi_agent_systems) Orchestrer efficacement plusieurs agents est crucial pour construire des systèmes multi-agents puissants. En combinant des agents avec différentes capacités (comme un agent de recherche web avec un agent d'exécution de code par exemple) vous pouvez créer des solutions plus sophistiquées. Ce module se concentre sur la conception, l'implémentation et la gestion de systèmes multi-agents pour maximiser l'efficacité et la fiabilité. ### 7️⃣ [Agents de vision et de navigation](./vision_agents) Les agents vision étendent les capacités traditionnelles des agents en incorporant des **modèles de vision-langage (*VLM* pour *Vision-Language Models*)**, leur permettant de traiter et d'interpréter des informations visuelles. Ce module explore comment concevoir et intégrer des agents alimentés par un *VLM*, débloquant des fonctionnalités avancées comme le raisonnement basé sur l'image, l'analyse de données visuelles et les interactions multimodales. Nous utiliserons également de tels agents pour construire un agent de navigation qui peut parcourir le web et en extraire des informations. ## Ressources - [Documentation smolagents](https://huggingface.co/docs/smolagents) - Documentation officielle de la bibliothèque smolagents - [Building Effective Agents](https://www.anthropic.com/research/building-effective-agents) - Article de recherche sur les architectures d'agents - [Directives pour les agents](https://huggingface.co/docs/smolagents/tutorials/building_good_agents) - Meilleures pratiques pour construire des agents fiables - [Agents LangGraph](https://langchain-ai.github.io/langgraph/) - Exemples supplémentaires d'implémentations d'agents - [Guide d'appel de fonctions](https://platform.openai.com/docs/guides/function-calling) - Comprendre l'appel de fonctions avec des LLM - [Meilleures pratiques RAG](https://www.pinecone.io/learn/retrieval-augmented-generation/) - Guide pour implémenter un RAG efficace ================================================ FILE: units/fr/unit2/smolagents/multi_agent_systems.mdx ================================================ # Systèmes multi-agents Les systèmes multi-agents permettent à des **agents spécialisés de collaborer sur des tâches complexes**, améliorant la modularité, la scalabilité et la robustesse. Au lieu de s'appuyer sur un seul agent, les tâches sont distribuées entre des agents ayant des capacités distinctes. Dans `smolagents`, différents agents peuvent être combinés pour générer du code Python, appeler des outils externes, effectuer des recherches web et plus encore. En orchestrant ces agents, nous pouvons créer des flux de travail puissants. Une configuration typique pourrait inclure : - Un **agent manageur** pour la délégation des tâches - Un **agent interpréteur de code** pour l'exécution de code - Un **agent de recherche web** pour la récupération d'informations Le diagramme ci-dessous illustre une architecture multi-agents simple où un **agent manageur** coordonne un **outil interpréteur de code** et un **agent de recherche web**, qui à son tour utilise des outils comme `DuckDuckGoSearchTool` et `VisitWebpageTool` pour rassembler des informations pertinentes. ## Systèmes multi-agents en action Un système multi-agents se compose de plusieurs agents spécialisés travaillant ensemble sous la coordination d'un **agent orchestrateur**. Cette approche permet des flux de travail complexes en distribuant les tâches entre des agents ayant des rôles distincts. Par exemple, un **système de RAG multi-agents** peut intégrer : - Un **agent web** pour naviguer sur internet. - Un **agent récupérateur** pour récupérer des informations à partir de bases de connaissances. - Un **agent de génération d'images** pour produire des visuels. Tous ces agents opèrent sous un orchestrateur qui gère la délégation de tâches et l'interaction. ## Résoudre une tâche complexe avec une hiérarchie multi-agents > [!TIP] > Vous pouvez suivre le code dans ce notebook que vous pouvez exécuter avec Google Colab. La réception approche ! Avec votre aide, Alfred a presque terminé les préparatifs. Mais maintenant il y a un problème : la Batmobile a disparu. Alfred doit trouver une remplaçante, et la trouver rapidement. Heureusement, quelques biographies ont été réalisées sur la vie de Bruce Wayne, alors peut-être qu'Alfred pourrait récupérer une voiture abandonnée sur l'un des plateaux de tournage et la reconditionner selon les normes modernes, ce qui inclurait certainement une option de conduite entièrement autonome. Mais cela pourrait être n'importe où dans les lieux de tournage autour du monde ; pouvant être nombreux. Donc Alfred nécessite votre aide. Pourriez-vous construire un agent capable de résoudre cette tâche ? > 👉 Trouvez tous les lieux de tournage de Batman dans le monde, calculez le temps de transfert par cargo jusqu'à ces lieux, et représentez-les sur une carte, avec une couleur variant en fonction du temps de transfert par cargo. Représentez également quelques usines de supercars avec le même temps de transfert en cargo. Construisons cela ! Cet exemple nécessite des packages supplémentaires, donc installons-les d'abord : ```bash pip install 'smolagents[litellm]' plotly geopandas shapely kaleido -q ``` ### Nous créons d'abord un outil pour obtenir le temps de transfert en avion cargo. ```python import math from typing import Optional, Tuple from smolagents import tool @tool def calculate_cargo_travel_time( origin_coords: Tuple[float, float], destination_coords: Tuple[float, float], cruising_speed_kmh: Optional[float] = 750.0, # Vitesse moyenne pour les avions cargo ) -> float: """ Calcule le temps de voyage pour un avion cargo entre deux points sur Terre en utilisant la distance du grand cercle. Args: origin_coords: Tuple de (latitude, longitude) pour le point de départ destination_coords: Tuple de (latitude, longitude) pour la destination cruising_speed_kmh: Vitesse de croisière optionnelle en km/h (par défaut 750 km/h pour les avions cargo typiques) Returns: float: Le temps de voyage estimé en heures Example: >>> # Chicago (41.8781° N, 87.6298° W) vers Sydney (33.8688° S, 151.2093° E) >>> result = calculate_cargo_travel_time((41.8781, -87.6298), (-33.8688, 151.2093)) """ def to_radians(degrees: float) -> float: return degrees * (math.pi / 180) # Extraire les coordonnées lat1, lon1 = map(to_radians, origin_coords) lat2, lon2 = map(to_radians, destination_coords) # Rayon de la Terre en kilomètres EARTH_RADIUS_KM = 6371.0 # Calculer la distance du grand cercle en utilisant la formule de haversine dlon = lon2 - lon1 dlat = lat2 - lat1 a = ( math.sin(dlat / 2) ** 2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2) ** 2 ) c = 2 * math.asin(math.sqrt(a)) distance = EARTH_RADIUS_KM * c # Ajouter 10% pour tenir compte des routes non directes et des contrôles de trafic aérien actual_distance = distance * 1.1 # Calculer le temps de vol # Ajouter 1 heure pour les procédures de décollage et d'atterrissage flight_time = (actual_distance / cruising_speed_kmh) + 1.0 # Formater les résultats return round(flight_time, 2) print(calculate_cargo_travel_time((41.8781, -87.6298), (-33.8688, 151.2093))) ``` ### Configuration de l'agent Pour le fournisseur de modèle, nous utilisons Together AI, l'un des nouveaux [fournisseurs d'inférence sur le Hub](https://huggingface.co/blog/inference-providers) ! Le `GoogleSearchTool` utilise l'[API Serper](https://serper.dev) pour rechercher sur le web, cela nécessite donc soit d'avoir configuré la variable d'environnement `SERPAPI_API_KEY` et de passer `provider="serpapi"` ou d'avoir `SERPER_API_KEY` et de passer `provider=serper`. Si vous n'avez pas de fournisseur Serp API configuré, vous pouvez utiliser `DuckDuckGoSearchTool` mais attention il a une limite d'appels. ```python import os from PIL import Image from smolagents import CodeAgent, GoogleSearchTool, InferenceClientModel, VisitWebpageTool model = InferenceClientModel(model_id="Qwen/Qwen2.5-Coder-32B-Instruct", provider="together") ``` Nous pouvons commencer par créer un agent simple comme ligne de base pour nous donner un rapport simple. ```python task = """Trouvez tous les lieux de tournage de Batman dans le monde, calculez le temps de transfert par avion cargo jusqu'ici (nous sommes à Gotham, 40.7128° N, 74.0060° W), et renvoyez-les moi sous la forme d'un dataframe pandas. Donnez-moi aussi des usines de supercars avec le même temps de transfert par avion-cargo.""" ``` ```python agent = CodeAgent( model=model, tools=[GoogleSearchTool("serper"), VisitWebpageTool(), calculate_cargo_travel_time], additional_authorized_imports=["pandas"], max_steps=20, ) ``` ```python result = agent.run(task) ``` ```python result ``` Dans notre cas, il génère cette sortie : ```python | | Location | Travel Time to Gotham (hours) | |--|------------------------------------------------------|------------------------------| | 0 | Necropolis Cemetery, Glasgow, Scotland, UK | 8.60 | | 1 | St. George's Hall, Liverpool, England, UK | 8.81 | | 2 | Two Temple Place, London, England, UK | 9.17 | | 3 | Wollaton Hall, Nottingham, England, UK | 9.00 | | 4 | Knebworth House, Knebworth, Hertfordshire, UK | 9.15 | | 5 | Acton Lane Power Station, Acton Lane, Acton, UK | 9.16 | | 6 | Queensboro Bridge, New York City, USA | 1.01 | | 7 | Wall Street, New York City, USA | 1.00 | | 8 | Mehrangarh Fort, Jodhpur, Rajasthan, India | 18.34 | | 9 | Turda Gorge, Turda, Romania | 11.89 | | 10 | Chicago, USA | 2.68 | | 11 | Hong Kong, China | 19.99 | | 12 | Cardington Studios, Northamptonshire, UK | 9.10 | | 13 | Warner Bros. Leavesden Studios, Hertfordshire, UK | 9.13 | | 14 | Westwood, Los Angeles, CA, USA | 6.79 | | 15 | Woking, UK (McLaren) | 9.13 | ``` Nous pourrions déjà l'améliorer un peu en ajoutant des étapes de planification dédiées et en ajoutant davantage de *prompts*. Les étapes de planification permettent à l'agent de penser à l'avance et planifier ses prochaines étapes, ce qui peut être utile pour des tâches plus complexes. ```python agent.planning_interval = 4 detailed_report = agent.run(f""" Vous êtes un analyste expert. Vous rédigez des rapports complets après avoir visité de nombreux sites web. N'hésitez pas à effectuer plusieurs recherches à la fois dans une boucle for. Pour chaque point de données que vous trouvez, visitez l'url source pour confirmer les chiffres. {task} """) print(detailed_report) ``` ```python detailed_report ``` Dans notre cas, il génère cette sortie : ```python | | Location | Travel Time (hours) | |--|--------------------------------------------------|---------------------| | 0 | Bridge of Sighs, Glasgow Necropolis, Glasgow, UK | 8.6 | | 1 | Wishart Street, Glasgow, Scotland, UK | 8.6 | ``` Grâce à ces changements rapides, nous avons obtenu un rapport beaucoup plus concis en fournissant simplement à notre agent un *prompt* détaillé, et en lui donnant des capacités de planification ! La fenêtre de contexte du modèle se remplit rapidement. Donc **si nous demandons à notre agent de combiner les résultats de recherche détaillée avec une autre, il sera plus lent et cela augmentera rapidement le nombre de *tokens* utilisés et donc les coûts**. ➡️ Nous devons améliorer la structure de notre système. ### ✌️ Diviser la tâche entre deux agents Les structures multi-agents permettent de séparer les mémoires entre différentes sous-tâches, avec deux grands avantages : - Chaque agent est davantage focalisé sur sa tâche principale, donc plus performant - Séparer les mémoires réduit le nombre de *tokens* d'entrée à chaque étape, réduisant ainsi la latence et le coût. Créons une équipe avec un agent de recherche web dédié, géré par un autre agent. L'agent gestionnaire devrait avoir des capacités de traçage pour écrire son rapport final : donnons-lui donc accès à des importations supplémentaires, incluant `plotly`, et `geopandas` + `shapely` pour le traçage spatial. ```python model = InferenceClientModel( "Qwen/Qwen2.5-Coder-32B-Instruct", provider="together", max_tokens=8096 ) web_agent = CodeAgent( model=model, tools=[ GoogleSearchTool(provider="serper"), VisitWebpageTool(), calculate_cargo_travel_time, ], name="web_agent", description="Navigue sur le web pour trouver des informations", verbosity_level=0, max_steps=10, ) ``` L'agent gestionnaire aura besoin de faire du travail mental intensif. Donc nous lui donnons le modèle plus puissant [DeepSeek-R1](https://huggingface.co/deepseek-ai/DeepSeek-R1), et ajoutons un `planning_interval` au mélange. ```python from smolagents.utils import encode_image_base64, make_image_url from smolagents import OpenAIServerModel def check_reasoning_and_plot(final_answer, agent_memory): multimodal_model = OpenAIServerModel("gpt-4o", max_tokens=8096) filepath = "saved_map.png" assert os.path.exists(filepath), "Assurez-vous de sauvegarder le graphique sous saved_map.png !" image = Image.open(filepath) prompt = ( f"Voici une tâche donnée par l'utilisateur et les étapes de l'agent : {agent_memory.get_succinct_steps()}. Maintenant voici le graphique qui a été fait." "Veuillez vérifier que le processus de raisonnement et le graphique sont corrects : répondent-ils correctement à la tâche donnée ?" "Listez d'abord les raisons pour lesquelles oui/non, puis écrivez votre décision finale : PASS en majuscules si c'est satisfaisant, FAIL si ce n'est pas le cas." "Ne soyez pas dur : si le graphique résout principalement la tâche, il devrait passer." "Pour passer, un graphique devrait être fait en utilisant px.scatter_map et non toute autre méthode (scatter_map a l'air plus joli)." ) messages = [ { "role": "user", "content": [ { "type": "text", "text": prompt, }, { "type": "image_url", "image_url": {"url": make_image_url(encode_image_base64(image))}, }, ], } ] output = multimodal_model(messages).content print("Feedback: ", output) if "FAIL" in output: raise Exception(output) return True manager_agent = CodeAgent( model=InferenceClientModel("deepseek-ai/DeepSeek-R1", provider="together", max_tokens=8096), tools=[calculate_cargo_travel_time], managed_agents=[web_agent], additional_authorized_imports=[ "geopandas", "plotly", "shapely", "json", "pandas", "numpy", ], planning_interval=5, verbosity_level=2, final_answer_checks=[check_reasoning_and_plot], max_steps=15, ) ``` Inspectons à quoi ressemble cette équipe : ```python manager_agent.visualize() ``` Cela générera quelque chose comme ceci, nous aidant à comprendre la structure et les relations entre les agents et les outils utilisés : ```python CodeAgent | deepseek-ai/DeepSeek-R1 ├── ✅ Importations autorisées : ['geopandas', 'plotly', 'shapely', 'json', 'pandas', 'numpy'] ├── 🛠️ Outils : │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ │ ┃ Nom ┃ Description ┃ Arguments ┃ │ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ │ calculate_cargo_travel_time │ Calcule le temps de voyage pour un │ origin_coords (`array`) : Tuple de │ │ │ │ avion cargo entre deux points sur │ (latitude, longitude) pour le │ │ │ │ Terre en utilisant la distance du │ point de départ │ │ │ │ grand cercle. │ destination_coords (`array`) : Tuple │ │ │ │ │ de (latitude, longitude) pour la │ │ │ │ │ destination │ │ │ │ │ cruising_speed_kmh (`number`) : │ │ │ │ │ Vitesse de croisière optionnelle │ │ │ │ │ en km/h (par défaut 750 km/h pour │ │ │ │ │ les avions cargo typiques) │ │ │ final_answer │ Fournit une réponse finale au problème │ answer (`any`) : La réponse finale │ │ │ │ donné. │ au problème │ │ └─────────────────────────────┴───────────────────────────────────────┴───────────────────────────────────────┘ └── 🤖 Agents gérés : └── web_agent | CodeAgent | Qwen/Qwen2.5-Coder-32B-Instruct ├── ✅ Importations autorisées : [] ├── 📝 Description : Navigue sur le web pour trouver des informations └── 🛠️ Outils : ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ Nom ┃ Description ┃ Arguments ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ web_search │ Effectue une recherche web Google │ query (`string`) : La requête de │ │ │ pour votre requête puis retourne │ recherche à effectuer. │ │ │ une chaîne des meilleurs résultats │ filter_year (`integer`) : │ │ │ de recherche. │ Optionnellement restreindre les │ │ │ │ résultats à une certaine année │ │ visit_webpage │ Visite une page web à l'URL donnée │ url (`string`) : L'URL de la page │ │ │ et lit son contenu comme une │ web à visiter. │ │ │ chaîne markdown. Utilisez ceci │ │ │ │ pour naviguer sur les pages web. │ │ │ calculate_cargo_travel_time │ Calcule le temps de voyage pour un │ origin_coords (`array`) : Tuple de │ │ │ avion cargo entre deux points sur │ (latitude, longitude) pour le │ │ │ Terre en utilisant la distance du │ point de départ │ │ │ grand cercle. │ destination_coords (`array`) : │ │ │ │ Tuple de (latitude, longitude) │ │ │ │ pour la destination │ │ │ │ cruising_speed_kmh (`number`) : │ │ │ │ Vitesse de croisière optionnelle │ │ │ │ en km/h (par défaut 750 km/h pour │ │ │ │ les avions cargo typiques) │ │ final_answer │ Fournit une réponse finale au │ answer (`any`) : La réponse finale │ │ │ problème donné. │ au problème │ └─────────────────────────────┴───────────────────────────────────┴───────────────────────────────────┘ ``` ```python manager_agent.run(""" Find all Batman filming locations in the world, calculate the time to transfer via cargo plane to here (we're in Gotham, 40.7128° N, 74.0060° W). Also give me some supercar factories with the same cargo plane transfer time. You need at least 6 points in total. Represent this as spatial map of the world, with the locations represented as scatter points with a color that depends on the travel time, and save it to saved_map.png! Here's an example of how to plot and return a map: import plotly.express as px df = px.data.carshare() fig = px.scatter_map(df, lat="centroid_lat", lon="centroid_lon", text="name", color="peak_hour", size=100, color_continuous_scale=px.colors.sequential.Magma, size_max=15, zoom=1) fig.show() fig.write_image("saved_image.png") final_answer(fig) Never try to process strings using code: when you have a string to read, just print it and you'll see it. """) ``` Je ne sais pas comment cela s'est passé pour votre exécution, mais dans la mienne, l'agent gestionnaire a habilement divisé les tâches données à l'agent web en `1. Rechercher les lieux de tournage de Batman`, puis `2. Trouver les usines de supercars`, avant d'agréger les listes et de tracer la carte. Voyons à quoi ressemble la carte en l'inspectant directement depuis l'état de l'agent : ```python manager_agent.python_executor.state["fig"] ``` Cela affichera la carte : ![Exemple de sortie de carte du système multi-agents](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/smolagents/output_map.png) ## Ressources - [Systèmes multi-agents](https://huggingface.co/docs/smolagents/main/en/examples/multiagents) – Aperçu des systèmes multi-agents. - [Qu'est-ce que le RAG agentique ?](https://weaviate.io/blog/what-is-agentic-rag) – Introduction au RAG agentique. - [Système RAG multi-agents 🤖🤝🤖 Recette](https://huggingface.co/learn/cookbook/multiagent_rag_system) – Guide étape par étape pour construire un système RAG multi-agents. ================================================ FILE: units/fr/unit2/smolagents/quiz1.mdx ================================================ # Petit Quiz (non noté) [[quiz1]] Testons votre compréhension de `smolagents` avec un rapide quiz ! N'oubliez pas, se tester aide à renforcer l'apprentissage et à identifier les domaines qui pourraient nécessiter une révision. Ceci est un quiz optionnel et il n'est pas noté. ### Q1 : Quel est l'un des principaux avantages de choisir `smolagents` par rapport à d'autres *frameworks* ? Quelle affirmation capture le mieux une force fondamentale de l'approche `smolagents` ? --- ### Q2 : Dans quel scénario bénéficieriez-vous probablement le plus de l'utilisation de smolagents ? Quelle situation s'aligne bien avec ce que *smolagents* fait de mieux ? --- ### Q3 : smolagents offre de la flexibilité dans l'intégration des modèles. Quelle affirmation reflète le mieux son approche ? Choisissez la description la plus précise de la façon dont *smolagents* interagit avec les LLM. --- ### Q4 : Comment smolagents gère-t-il le débat entre les actions basées sur le code et les actions basées sur du JSON ? Quelle affirmation caractérise correctement la philosophie de *smolagents* concernant les formats d'action ? --- ### Q5 : Comment smolagents s'intègre-t-il avec le Hub d'Hugging Face pour des bénéfices supplémentaires ? Quelle affirmation décrit avec précision l'un des avantages principaux de l'intégration avec le Hub ? --- Félicitations d'avoir terminé ce quiz ! 🎉 Si vous avez manqué des questions, envisagez de revoir la section *Pourquoi utiliser smolagents* pour une compréhension plus approfondie. Si vous avez bien réussi, vous êtes prêt à explorer des sujets plus avancés dans *smolagents* ! ================================================ FILE: units/fr/unit2/smolagents/quiz2.mdx ================================================ # Petit Quiz (non noté) [[quiz2]] Il est temps de tester votre compréhension des sections sur `CodeAgent`, `ToolCalling Agent` et les *Outils*. Ce quiz est optionnel et non noté. --- ### Q1 : Quelle est la différence clé entre créer un outil avec le décorateur `@tool` et créer une sous-classe de `Tool` dans smolagents ? Quelle déclaration décrit le mieux la distinction entre ces deux approches pour définir des outils ? @tool est obligatoire pour les outils basés sur la récupération, tandis que les sous-classes de Tool sont uniquement pour les tâches de génération de texte", explain: "Les deux approches peuvent être utilisées pour tout type d'outil, y compris les outils basés sur la récupération ou la génération de texte.", }, { text: "Le décorateur @tool est recommandé pour les outils simples basés sur des fonctions, tandis que les sous-classes de Tool offrent plus de flexibilité pour des fonctionnalités complexes ou des métadonnées personnalisées", explain: "C'est correct. L'approche par décorateur est plus simple, mais la sous-classe permet un comportement plus personnalisé.", correct: true }, { text: "@tool ne peut être utilisé que dans des systèmes multi-agents, tandis que créer une sous-classe de Tool est pour les scénarios à un seul agent", explain: "Tous les agents (simples ou multiples) peuvent utiliser l'une ou l'autre approche pour définir des outils ; il n'y a pas de telle restriction.", }, { text: "Décorer une fonction avec @tool remplace le besoin d'une docstring, tandis que les sous-classes ne doivent pas inclure de docstring", explain: "Les deux méthodes bénéficient de docstrings claires. Le décorateur ne les remplace pas, et une sous-classe peut toujours avoir des docstrings.", } ]} /> --- ### Q2 : Comment un `CodeAgent` gère-t-il les tâches multi-étapes en utilisant l'approche ReAct (*Reason + Act*) ? Quelle déclaration décrit correctement comment le CodeAgent exécute une série d'étapes pour résoudre une tâche ? CodeAgent lui-même peut gérer plusieurs étapes de manière autonome en utilisant ReAct.", }, { text: "Il stocke chaque action en JSON pour une analyse facile avant de les exécuter toutes en même temps", explain: "Ce comportement correspond à l'approche basée sur JSON du ToolCallingAgent, pas du CodeAgent.", }, { text: "Il alterne entre l'écriture de raisonnements internes, la génération de code Python, l'exécution du code et l'enregistrement des résultats jusqu'à arriver à une réponse finale", explain: "Correct. Cela décrit le schéma ReAct que CodeAgent utilise, incluant le raisonnement itératif et l'exécution de code.", correct: true }, { text: "Il s'appuie sur un module de vision pour valider la sortie du code avant de continuer à l'étape suivante", explain: "Les capacités de vision sont supportées dans smolagents, mais elles ne sont pas une exigence par défaut pour CodeAgent ou l'approche ReAct.", } ]} /> --- ### Q3 : Lequel des éléments suivants est un avantage principal du partage d'un outil sur le Hub d'Hugging Face ? Sélectionnez la meilleure raison pour laquelle un développeur pourrait télécharger et partager son outil personnalisé. MultiStepAgent pour la génération augmentée par récupération", explain: "Partager un outil ne configure pas automatiquement la récupération ou la logique multi-étapes. Il s'agit simplement de rendre l'outil disponible.", }, { text: "Cela permet aux autres de découvrir, réutiliser et intégrer votre outil dans leurs agent construit avec smolagents sans configuration supplémentaire", explain: "Oui. Partager sur le Hub rend les outils accessibles pour quiconque (y compris vous-même) de les télécharger et les réutiliser rapidement.", correct: true }, { text: "Cela garantit que seuls les CodeAgent peuvent invoquer l'outil tandis que les ToolCallingAgent ne le peuvent pas", explain: "Les CodeAgents et les ToolCallingAgents peuvent tous deux invoquer des outils partagés. Il n'y a pas de restriction par type d'agent.", }, { text: "Cela convertit votre outil en une fonction entièrement capable de vision pour le traitement d'images", explain: "Le partage d'outils ne modifie pas la fonctionnalité de l'outil ni n'ajoute automatiquement des capacités de vision.", } ]} /> --- ### Q4 : `ToolCallingAgent` diffère de `CodeAgent` dans la façon dont il exécute les actions. Quelle déclaration est correcte ? Choisissez l'option qui décrit avec précision comment ToolCallingAgent fonctionne. ToolCallingAgent est uniquement compatible avec un système multi-agents, tandis que CodeAgent peut fonctionner seul", explain: "L'un ou l'autre agent peut être utilisé seul ou dans le cadre d'un système multi-agents.", }, { text: "ToolCallingAgent délègue tout le raisonnement à un agent de récupération séparé, puis retourne une réponse finale", explain: "ToolCallingAgent utilise toujours un LLM principal pour le raisonnement ; il ne se fie pas uniquement aux agents de récupération.", }, { text: "ToolCallingAgent génère des instructions JSON spécifiant les appels d'outils et les arguments, qui sont ensuite analysés et exécutés", explain: "C'est correct. ToolCallingAgent utilise l'approche JSON pour définir les appels d'outils.", correct: true }, { text: "ToolCallingAgent est uniquement destiné aux tâches à une seule étape et s'arrête automatiquement après avoir appelé un outil", explain: "ToolCallingAgent peut effectuer plusieurs étapes si nécessaire, tout comme CodeAgent.", } ]} /> --- ### Q5 : Qu'est-ce qui est inclus dans la boîte à outils par défaut de smolagents, et pourquoi pourriez-vous l'utiliser ? Quelle déclaration capture le mieux l'objectif et le contenu de la boîte à outils par défaut dans smolagents ? PythonInterpreterTool et un outil de réponse finale pour un prototypage rapide", explain: "Correct. La boîte à outils par défaut contient ces outils prêts à l'emploi pour une intégration facile lors de la construction d'agents.", correct: true }, { text: "Elle ne supporte que les tâches basées sur la vision comme la classification d'images ou l'OCR par défaut", explain: "Bien que smolagents puisse intégrer des fonctionnalités basées sur la vision, la boîte à outils par défaut n'est pas exclusivement orientée vision.", }, { text: "Elle est destinée uniquement aux systèmes multi-agents et est incompatible avec un seul CodeAgent", explain: "La boîte à outils par défaut peut être utilisée par tout type d'agent, configurations simples ou multi-agents.", }, { text: "Elle ajoute des fonctionnalités avancées basées sur la récupération pour la réponse à des questions à grande échelle à partir d'un magasin de vecteurs", explain: "Bien que vous puissiez construire des outils de récupération, la boîte à outils par défaut ne fournit pas automatiquement des fonctionnalités de RAG avancées.", } ]} /> --- Félicitations pour avoir terminé ce quiz ! 🎉 Si des questions vous ont posé des difficultés, revisitez les sections `CodeAgent`, `ToolCalling Agent` ou *Outils* pour renforcer votre compréhension. Si vous l'avez réussi, vous êtes bien parti pour construire des applications robustes avec `smolagents` ! ================================================ FILE: units/fr/unit2/smolagents/retrieval_agents.mdx ================================================ # Construction de systèmes de RAG agentiques > [!TIP] > Vous pouvez suivre le code dans ce notebook que vous pouvez exécuter avec Google Colab. Les systèmes de RAG (*Retrieval Augmented Generation*) combinent les capacités de récupération de données et de modèles de génération pour fournir des réponses contextuelles. Par exemple, la requête d'un utilisateur est transmise à un moteur de recherche puis les résultats récupérés sont fournis au LLM avec la requête. Le modèle génère ensuite une réponse basée sur la requête et les informations récupérées. Le RAG agentique (*Agentic RAG*) étend les systèmes de RAG traditionnels en **combinant des agents autonomes avec une récupération dynamique des connaissances**. Alors que les systèmes de RAG traditionnels utilisent un LLM pour répondre aux requêtes basées sur des données récupérées, le RAG agentique **permet un contrôle intelligent des processus de récupération et de génération**, améliorant l'efficacité et la précision. Les systèmes de RAG traditionnels font face à des limitations clés, telles que **s'appuyer sur une seule étape de récupération** et se concentrer sur la similarité sémantique directe avec la requête de l'utilisateur, ce qui peut négliger des informations pertinentes. Le RAG agentique résout ces problèmes en permettant à l'agent de formuler de manière autonome des requêtes, de critiquer les résultats récupérés et de mener plusieurs étapes de récupération pour une sortie plus adaptée et complète. ## Récupération de base avec DuckDuckGo Construisons un agent simple qui peut rechercher sur le web en utilisant DuckDuckGo. Cet agent récupérera des informations et synthétisera des réponses pour répondre aux requêtes. Avec le RAG agentique, l'agent d'Alfred peut : * Rechercher des dernières tendances en matière de fêtes de super-héros * Affiner les résultats pour inclure des éléments luxueux * Synthétiser les informations en un plan complet Voici comment l'agent d'Alfred peut y parvenir : ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel # Initialiser l'outil de recherche search_tool = DuckDuckGoSearchTool() # Initialiser le modèle model = InferenceClientModel() agent = CodeAgent( model=model, tools=[search_tool], ) # Exemple d'utilisation response = agent.run( "Search for luxury superhero-themed party ideas, including decorations, entertainment, and catering." ) print(response) ``` L'agent suit ce processus : 1. **Analyse la requête :** identifie les éléments clés de la requête - organisation de fêtes de luxe sur le thème des super-héros, en mettant l'accent sur la décoration, les divertissements et la restauration. 2. **Effectue la récupération :** exploite DuckDuckGo pour rechercher les informations les plus pertinentes et à jour, en s'assurant qu'elles correspondent aux préférences d'Alfred pour un événement luxueux. 3. **Synthétise l'information :** après avoir rassemblé les résultats, l'agent les traite en un plan cohérent et actionnable pour Alfred, couvrant tous les aspects de la fête. 4. **Stocke pour référence future :** stocke les informations récupérées pour un accès facile lors de la planification d'événements futurs, optimisant l'efficacité des tâches ultérieures. ## Outil de base de connaissances personnalisé Pour des tâches spécialisées, une base de connaissances personnalisée peut être inestimable. Créons un outil qui interroge une base de données vectorielle de documentation technique ou de connaissances spécialisées. En utilisant la recherche sémantique, l'agent peut trouver les informations les plus pertinentes pour les besoins d'Alfred. Une base de données vectorielle stocke des représentations numériques (*embeddings*) de texte ou d'autres données, créées par des modèles d'apprentissage automatique. Elle permet la recherche sémantique en identifiant des significations similaires dans un espace de haute dimension. Cette approche combine des connaissances prédéfinies avec une recherche sémantique pour fournir des solutions contextuelles pour la planification d'événements. Avec un accès à des connaissances spécialisées, Alfred peut perfectionner chaque détail de la fête. Dans cet exemple, nous allons créer un outil qui récupère des idées de planification de fête à partir d'une base de connaissances personnalisée. Nous utiliserons un modèle BM25 pour rechercher dans la base de connaissances et retourner les meilleurs résultats, et `RecursiveCharacterTextSplitter` pour diviser les documents en morceaux plus petits pour une recherche plus efficace. ```python from langchain.docstore.document import Document from langchain.text_splitter import RecursiveCharacterTextSplitter from smolagents import Tool from langchain_community.retrievers import BM25Retriever from smolagents import CodeAgent, InferenceClientModel class PartyPlanningRetrieverTool(Tool): name = "party_planning_retriever" description = "Utilise la recherche sémantique pour trouver des idées pertinentes pour l'organisation de la fête d'Alfred au Manoir Wayne sur le thème des super-héros." inputs = { "query": { "type": "string", "description": "La requête à effectuer. Celle-ci doit être liée à l'organisation de fêtes ou à des thèmes de super-héros.", } } output_type = "string" def __init__(self, docs, **kwargs): super().__init__(**kwargs) self.retriever = BM25Retriever.from_documents( docs, k=5 # Récupérer les 5 meilleurs documents ) def forward(self, query: str) -> str: assert isinstance(query, str), "Votre requête doit être une chaîne de caractères" docs = self.retriever.invoke( query, ) return "\nIdées récupérées :\n" + "".join( [ f"\n\n===== Idée {str(i)} =====\n" + doc.page_content for i, doc in enumerate(docs) ] ) # Simuler une base de connaissances sur la planification de la fête party_ideas = [ {"text": "Un bal masqué sur le thème des super-héros avec un décor luxueux, notamment des accents dorés et des rideaux de velours.", "source": "Idées de fête 1"}, {"text": "Engagez un DJ professionnel qui peut jouer de la musique sur le thème des super-héros comme Batman et Wonder Woman.", "source": "Idées de divertissement"}, {"text": "Pour la restauration, servez des plats portant le nom de super-héros, comme 'Le smoothie vert de Hulk' et 'Le steak de puissance d'Iron Man'", "source": "Idées de traiteur"}, {"text": "Décorez le lieu avec des logos de super-héros emblématiques et des projections de Gotham et d'autres villes de super-héros.", "source": "Idées de décoration"}, {"text": "Expériences interactives avec la VR où les invités peuvent participer à des simulations de super-héros ou à des jeux à thème.", "source": "Idées de divertissement"} ] source_docs = [ Document(page_content=doc["text"], metadata={"source": doc["source"]}) for doc in party_ideas ] # Découper les documents en morceaux plus petits pour une recherche plus efficace text_splitter = RecursiveCharacterTextSplitter( chunk_size=500, chunk_overlap=50, add_start_index=True, strip_whitespace=True, separators=["\n\n", "\n", ".", " ", ""], ) docs_processed = text_splitter.split_documents(source_docs) # Créer l'outil de récupération party_planning_retriever = PartyPlanningRetrieverTool(docs_processed) # Initialiser l'agent agent = CodeAgent(tools=[party_planning_retriever], model=InferenceClientModel()) # Exemple d'utilisation response = agent.run( "Trouver des idées pour une fête de luxe sur le thème des super-héros, y compris des options de divertissement, de restauration et de décoration." ) print(response) ``` Cet agent amélioré peut : 1. D'abord vérifier la documentation pour des informations pertinentes 2. Combiner les informations de la base de connaissances 3. Maintenir le contexte de conversation en mémoire ## Capacités de récupération améliorées Lors de la construction de systèmes de RAG agentiques, l'agent peut employer des stratégies sophistiquées comme : 1. **La reformulation de requête :** Au lieu d'utiliser la requête brute de l'utilisateur, l'agent peut élaborer des termes de recherche optimisés qui correspondent mieux aux documents cibles 2. **La décomposition de requête :** Au lieu d'utiliser directement la requête de l'utilisateur, si elle contient plusieurs éléments d'information à interroger, elle peut être décomposée en plusieurs requêtes 3. **L'expansion de requête :** Similaire à la reformulation de requête mais effectuée plusieurs fois pour formuler la requête de plusieurs façons et les interroger toutes 4. **Le reclassement :** Utiliser des [*Cross-Encoders*](https://huggingface.co/models?pipeline_tag=text-ranking&sort=trending) pour attribuer des scores de pertinence sémantique plus complets entre les documents récupérés et la requête 5. **La récupération multi-étapes :** L'agent peut effectuer plusieurs recherches, en utilisant les résultats initiaux pour informer les requêtes suivantes 6. **L'intégration de sources :** Les informations peuvent être combinées à partir de plusieurs sources comme la recherche web et la documentation locale 7. **La validation des résultats :** Le contenu récupéré peut être analysé pour sa pertinence et son exactitude avant d'être inclus dans les réponses Les systèmes de RAG agentiques efficaces nécessitent une considération attentive de plusieurs aspects clés. L'agent **devrait sélectionner entre les outils disponibles en fonction du type de requête et du contexte**. Les systèmes de mémoire aident à maintenir l'historique de conversation et évitent les récupérations répétitives. Avoir des stratégies de secours garantit que le système peut toujours fournir de la valeur même lorsque les méthodes de récupération principales échouent. De plus, l'implémentation d'étapes de validation aide à assurer l'exactitude et la pertinence des informations récupérées. ## Ressources - [Agentic RAG : boostez votre RAG avec la reformulation de requête et l'auto-requête ! 🚀](https://huggingface.co/learn/cookbook/agent_rag) - Recette pour développer un système de RAG agentique en utilisant `smolagents`. ================================================ FILE: units/fr/unit2/smolagents/tool_calling_agents.mdx ================================================ # Écrire des actions sous forme d'extraits de code ou de blobs JSON > [!TIP] > Vous pouvez suivre le code dans ce notebook que vous pouvez exécuter avec Google Colab. Les `ToolCallingAgent` sont le deuxième type d'agent disponible dans `smolagents`. Contrairement aux `CodeAgent` qui utilisent des extraits de code en Python, ces agents **utilisent les capacités d'appel d'outils intégrées des fournisseurs de LLM** pour générer des appels d'outils sous forme de **structures JSON**. C'est l'approche standard utilisée par OpenAI, Anthropic et de nombreux autres fournisseurs. Regardons un exemple. Quand Alfred veut rechercher des services de restauration et des idées de fête, un `CodeAgent` générerait et exécuterait du code Python comme ceci : ```python for query in [ "Meilleurs services de restauration à Gotham City", "Idées de thème de fête pour super-héros" ]: print(web_search(f"Rechercher : {query}")) ``` Un `ToolCallingAgent` créerait plutôt une structure JSON : ```python [ {"name": "web_search", "arguments": "Meilleurs services de restauration à Gotham City"}, {"name": "web_search", "arguments": "Idées de thème de fête pour super-héros"} ] ``` Ce blob JSON est ensuite utilisé pour exécuter les appels d'outils. Bien que `smolagents` se concentre principalement sur les `CodeAgent` puisqu'[ils performent mieux dans l'ensemble](https://huggingface.co/papers/2402.01030), les `ToolCallingAgent` peuvent être efficaces pour des systèmes simples qui ne nécessitent pas de gestion de variables ou d'appels d'outils complexes. ![Code vs JSON Actions](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/code_vs_json_actions.png) ## Comment fonctionnent *ToolCallingAgent* ? Les `ToolCallingAgent` suivent le même *workflow* multi-étapes que les `CodeAgent` (voir la [section précédente](./code_agents) pour plus de détails). La différence clé est dans **la façon dont ils structurent leurs actions** : au lieu de code exécutable, ils **génèrent des objets JSON qui spécifient les noms d'outils et les arguments**. Le système **analyse ensuite ces instructions** pour exécuter les outils appropriés. ## Exemple : exécuter un *ToolCallingAgent* Revisitions l'exemple précédent où Alfred a commencé les préparatifs de la fête, mais cette fois nous utiliserons un `ToolCallingAgent` pour mettre en évidence la différence. Nous allons construire un agent qui peut rechercher sur le web en utilisant DuckDuckGo, tout comme dans notre exemple de `CodeAgent`. La seule différence est le type d'agent ; le *framework* gère tout le reste : ```python from smolagents import ToolCallingAgent, DuckDuckGoSearchTool, InferenceClientModel agent = ToolCallingAgent(tools=[DuckDuckGoSearchTool()], model=InferenceClientModel()) agent.run("Recherche les meilleures recommandations musicales pour une fête au manoir des Wayne.") ``` Lorsque vous examinez la trace de l'agent, au lieu de voir `Executing parsed code:`, vous verrez quelque chose comme : ```text ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ Calling tool: 'web_search' with arguments: {'query': "meilleures recommandations musicales pour une fête au │ │ manoir des Wayne"} │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ``` L'agent génère un appel d'outil structuré que le système traite pour produire la sortie, plutôt que d'exécuter directement du code. Maintenant que nous comprenons les deux types d'agents, nous pouvons choisir celui adapté à nos besoins. Continuons à explorer `smolagents` pour faire de la fête d'Alfred un succès ! 🎉 ## Ressources - [Documentation ToolCallingAgent](https://huggingface.co/docs/smolagents/v1.8.1/en/reference/agents#smolagents.ToolCallingAgent) - Documentation officielle de `ToolCallingAgent` ================================================ FILE: units/fr/unit2/smolagents/tools.mdx ================================================ # Outils Comme nous l'avons exploré dans [l'Unité 1](https://huggingface.co/learn/agents-course/fr/unit1/introduction), les agents utilisent des outils pour effectuer diverses actions. Dans `smolagents`, les outils sont traités comme des **fonctions qu'un *LLM* peut appeler au sein d'un système d'agent**. Pour interagir avec un outil, le *LLM* a besoin d'une **description d'interface** avec ces composants clés : - **Nom** : Comment l'outil s'appelle - **Description de l'outil** : Ce que fait l'outil - **Types et descriptions des entrées** : Quels arguments l'outil accepte - **Type de sortie** : Ce que l'outil retourne Par exemple, pendant qu'il se prépare pour une fête au manoir Wayne, Alfred a besoin de divers outils pour recueillir des informations : de la recherche de services de traiteur à la recherche d'idées de thèmes de fête. Voici à quoi pourrait ressembler l'interface d'un simple outil de recherche : - **Nom :** `web_search` - **Description de l'outil :** Recherche sur le web des requêtes spécifiques - **Entrée :** `query` (string) - Le terme de recherche à rechercher - **Sortie :** String contenant les résultats de recherche En utilisant ces outils, Alfred peut prendre des décisions éclairées et rassembler toutes les informations nécessaires pour planifier la fête parfaite. Ci-dessous, vous pouvez voir une animation illustrant comment un appel d'outil est géré : ![Pipeline agentique de https://huggingface.co/docs/smolagents/conceptual_guides/react](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/Agent_ManimCE.gif) ## Méthodes de création d'outils Dans `smolagents`, les outils peuvent être définis de deux façons : 1. **En utilisant le décorateur `@tool`** pour des outils simples basés sur des fonctions 2. **En créant une sous-classe de `Tool`** pour des fonctionnalités plus complexes ### Le décorateur `@tool` Le décorateur `@tool` est la **méthode recommandée pour définir des outils simples**. Sous le capot, `smolagents` analysera les informations de base sur la fonction à partir de Python. Donc si vous nommez votre fonction clairement et écrivez une bonne *docstring*, il sera plus facile pour le *LLM* de l'utiliser. En utilisant cette approche, nous définissons une fonction avec : - **Un nom de fonction clair et descriptif** qui aide le *LLM* à comprendre son objectif. - **Des indications de type pour les entrées et les sorties** pour assurer une utilisation correcte. - **Une description détaillée**, incluant une section `Args:` où chaque argument est explicitement décrit. Ces descriptions fournissent un contexte précieux pour le *LLM*, il est donc important de les écrire soigneusement. #### Générer un outil qui récupère le service de traiteur le mieux noté Alfred Catering > [!TIP] > Vous pouvez suivre le code dans ce notebook que vous pouvez exécuter avec Google Colab. Imaginons qu'Alfred ait déjà décidé du menu pour la fête, mais qu'il ait maintenant besoin d'aide pour préparer la nourriture pour un si grand nombre d'invités. Pour ce faire, il aimerait engager un service de traiteur et doit identifier les options les mieux notées disponibles. Alfred peut utiliser un outil pour rechercher les meilleurs services de traiteur proche de chez lui. Voici un exemple de la façon dont Alfred peut utiliser le décorateur `@tool` pour y parvenir : ```python from smolagents import CodeAgent, InferenceClientModel, tool # Supposons que nous ayons une fonction qui recherche les services de restauration les mieux notés @tool def catering_service_tool(query: str) -> str: """ Cet outil retourne le service de traiteur le mieux noté à Gotham City. Args: query: Un terme de recherche pour trouver des services de traiteur. """ # Exemple de liste de services de traiteur et leurs notes services = { "Gotham Catering Co.": 4.9, "Wayne Manor Catering": 4.8, "Gotham City Events": 4.7, } # Trouver le service de traiteur le mieux noté (simulation du filtrage de requête de recherche) best_service = max(services, key=services.get) return best_service agent = CodeAgent(tools=[catering_service_tool], model=InferenceClientModel()) # Exécuter l'agent pour trouver le meilleur service de traiteur result = agent.run( "Can you give me the name of the highest-rated catering service in Gotham City?" ) print(result) # Sortie : Gotham Catering Co. ``` ### Définir un outil comme une classe Python Cette approche implique de créer une sous-classe de [`Tool`](https://huggingface.co/docs/smolagents/v1.8.1/en/reference/tools#smolagents.Tool). Pour des outils complexes, nous pouvons implémenter une classe au lieu d'une fonction Python. La classe encapsule la fonction avec des métadonnées qui aident le *LLM* à comprendre comment l'utiliser efficacement. Dans cette classe, nous définissons : - `name` : Le nom de l'outil. - `description` : Une description utilisée pour remplir le prompt système de l'agent. - `inputs` : Un dictionnaire avec les clés `type` et `description`, fournissant des informations pour aider l'interpréteur Python à traiter les entrées. - `output_type` : Spécifie le type de sortie attendu. - `forward` : La méthode contenant la logique d'inférence à exécuter. Ci-dessous, nous pouvons voir un exemple d'un outil construit en utilisant `Tool` et comment l'intégrer dans un `CodeAgent`. #### Générer un outil pour générer des idées pour une fête sur le thème des super-héros La fête d'Alfred au manoir est un **événement à thème portant sur les super-héros**, mais il a besoin d'idées créatives pour la rendre vraiment spéciale. En tant qu'hôte fantastique, il veut surprendre les invités avec un thème unique. Pour ce faire, il peut utiliser un agent qui génère des idées de fêtes sur le thème des super-héros en fonction d'une catégorie donnée. De cette façon, Alfred peut trouver le thème de fête parfait pour épater ses invités. ```python from smolagents import Tool, CodeAgent, InferenceClientModel class SuperheroPartyThemeTool(Tool): name = "superhero_party_theme_generator" description = """ Cet outil propose des idées de fêtes créatives sur le thème des super-héros en fonction d'une catégorie. Il retourne une idée de thème de fête unique.""" inputs = { "category": { "type": "string", "description": "Le type de fête de super-héros (par exemple, 'classic heroes', 'villain masquerade', 'futuristic Gotham').", } } output_type = "string" def forward(self, category: str): themes = { "classic heroes": "Justice League Gala : Les invités viennent habillés en leurs héros DC préférés avec des cocktails à thème comme 'The Kryptonite Punch'.", "villain masquerade": "Gotham Rogues' Ball : Un bal masqué mystérieux où les invités s'habillent en méchants classiques de Batman.", "futuristic Gotham": "Neo-Gotham Night : Une fête de style cyberpunk inspirée de Batman Beyond, avec des décorations néon et des gadgets futuristes." } return themes.get(category.lower(), "Idée de fête à thème non trouvée. Essayez 'classic heroes', 'villain masquerade', ou 'futuristic Gotham'.") # Instancier l'outil party_theme_tool = SuperheroPartyThemeTool() agent = CodeAgent(tools=[party_theme_tool], model=InferenceClientModel()) # Exécuter l'agent pour générer une idée de thème de fête result = agent.run( "What would be a good superhero party idea for a 'villain masquerade' theme?" ) print(result) # Sortie : "Gotham Rogues' Ball : Un bal masqué mystérieux où les invités s'habillent en méchants classiques de Batman." ``` Avec cet outil, Alfred sera le super hôte par excellence, impressionnant ses invités avec une fête sur le thème des super-héros qu'ils n'oublieront pas ! 🦸‍♂️🦸‍♀️ ## Boîte à outils par défaut `smolagents` est livré avec un ensemble d'outils pré-construits qui peuvent être directement injectés dans votre agent. La [boîte à outils par défaut](https://huggingface.co/docs/smolagents/guided_tour?build-a-tool=Decorate+a+function+with+%40tool#default-toolbox) comprend : - **PythonInterpreterTool** - **FinalAnswerTool** - **UserInputTool** - **DuckDuckGoSearchTool** - **GoogleSearchTool** - **VisitWebpageTool** Alfred peut utiliser divers outils pour assurer une fête parfaite au manoir Wayne : - D'abord, il pourrait utiliser le `DuckDuckGoSearchTool` pour trouver des idées créatives de fête sur le thème des super-héros. - Pour le traiteur, il se fierait au `GoogleSearchTool` pour trouver les services les mieux notés à Gotham. - Pour gérer la disposition des tables, Alfred pourrait effectuer des calculs avec l'outil `PythonInterpreterTool`. - Une fois que tout est rassemblé, il compilerait le plan en utilisant `FinalAnswerTool`. Grâce à ces outils, Alfred garantit que la fête sera à la fois exceptionnelle et harmonieuse. 🦇💡 ## Partage et importation d'outils L'une des fonctionnalités les plus puissantes de `smolagents` est sa capacité à partager des outils personnalisés sur le Hub et à intégrer de manière transparente des outils créés par la communauté. Cela inclut la connexion avec les **Spaces** d'Hugging Face et les **outils LangChain**, améliorant considérablement la capacité d'Alfred à orchestrer une fête inoubliable. 🎭 Avec ces intégrations, Alfred peut exploiter des outils avancés de planification d'événements ; qu'il s'agisse d'ajuster l'éclairage pour l'ambiance parfaite, de créer la *playlist* idéale pour la fête, ou de coordonner avec les meilleurs traiteurs de Gotham. Voici des exemples montrant comment ces fonctionnalités peuvent améliorer l'expérience de la fête : ### Partager un outil sur le Hub Partager votre outil personnalisé avec la communauté est facile ! Il suffit de le télécharger sur votre compte Hugging Face en utilisant la méthode `push_to_hub()`. Par exemple, Alfred peut partager son `party_theme_tool` pour aider les autres à trouver les meilleurs services de traiteur à Gotham. Voici comment faire : ```python party_theme_tool.push_to_hub("{your_username}/party_theme_tool", token="") ``` ### Importer un outil depuis le Hub Vous pouvez facilement importer des outils créés par d'autres utilisateurs en utilisant la fonction `load_tool()`. Par exemple, Alfred pourrait vouloir générer une image promotionnelle pour la fête en utilisant l'IA. Au lieu de construire un outil à partir de zéro, il peut exploiter un outil prédéfini de la communauté : ```python from smolagents import load_tool, CodeAgent, InferenceClientModel image_generation_tool = load_tool( "m-ric/text-to-image", trust_remote_code=True ) agent = CodeAgent( tools=[image_generation_tool], model=InferenceClientModel() ) agent.run("Generate an image of a luxurious superhero-themed party at Wayne Manor with made-up superheros.") ``` ### Importer un Space comme outil Vous pouvez également importer un *Space* comme outil en utilisant `Tool.from_space()`. Cela ouvre des possibilités d'intégration avec des milliers de *Spaces* de la communauté pour des tâches allant de la génération d'images à l'analyse de données. L'outil se connectera au *backend Gradio* des *Spaces* en utilisant le `gradio_client`, alors assurez-vous de l'installer via `pip` si vous ne l'avez pas déjà fait. Pour la fête, Alfred peut utiliser un *Space* existant pour la génération de l'image générée par IA à utiliser comme invitation (au lieu de l'outil pré-construit que nous avons mentionné précédemment). Construisons-le ! ```python from smolagents import CodeAgent, InferenceClientModel, Tool image_generation_tool = Tool.from_space( "black-forest-labs/FLUX.1-schnell", name="image_generator", description="Generate an image from a prompt" ) model = InferenceClientModel("Qwen/Qwen2.5-Coder-32B-Instruct") agent = CodeAgent(tools=[image_generation_tool], model=model) agent.run( "Improve this prompt, then generate an image of it.", additional_args={'user_prompt': 'A grand superhero-themed party at Wayne Manor, with Alfred overseeing a luxurious gala'} ) ``` ### Importer un outil LangChain Nous discuterons du *framework* `LangChain` dans les sections à venir. Pour l'instant, nous notons simplement que nous pouvons réutiliser des outils LangChain dans votre *workflow* `smolagents` ! Vous pouvez facilement charger des outils LangChain en utilisant la méthode `Tool.from_langchain()`. Alfred, toujours aussi perfectionniste, prépare une spectaculaire soirée de super-héros au manoir pendant l'absence des Wayne. Pour s'assurer que chaque détail dépasse les attentes, il utilise les outils LangChain pour trouver des idées de divertissement de premier ordre. En utilisant `Tool.from_langchain()`, Alfred ajoute sans effort des fonctionnalités de recherche avancées à son agent, lui permettant de découvrir des idées et services de fête exclusifs avec seulement quelques commandes. Voici comment il procède : ```python from langchain.agents import load_tools from smolagents import CodeAgent, InferenceClientModel, Tool search_tool = Tool.from_langchain(load_tools(["serpapi"])[0]) agent = CodeAgent(tools=[search_tool], model=model) agent.run("Search for luxury entertainment ideas for a superhero-themed event, such as live performances and interactive experiences.") ``` ### Importer une collection d'outils depuis n'importe quel serveur MCP `smolagents` permet également d'importer des outils depuis les centaines de serveurs MCP disponibles sur [glama.ai](https://glama.ai/mcp/servers) ou [smithery.ai](https://smithery.ai). Si vous voulez approfondir le MCP, vous pouvez consulter notre [cours gratuit](https://huggingface.co/learn/mcp-course/).
Installer le client mcp Nous devons d'abord installer l'intégration `mcp` pour `smolagents`. ```bash pip install "smolagents[mcp]" ```
Les outils des serveurs MCP peuvent être chargés dans un objet `ToolCollection` comme suit : ```python import os from smolagents import ToolCollection, CodeAgent from mcp import StdioServerParameters from smolagents import InferenceClientModel model = InferenceClientModel("Qwen/Qwen2.5-Coder-32B-Instruct") server_parameters = StdioServerParameters( command="uvx", args=["--quiet", "pubmedmcp@0.1.3"], env={"UV_PYTHON": "3.12", **os.environ}, ) with ToolCollection.from_mcp(server_parameters, trust_remote_code=True) as tool_collection: agent = CodeAgent(tools=[*tool_collection.tools], model=model, add_base_tools=True) agent.run("Please find a remedy for hangover.") ``` Grâce à cette configuration, Alfred peut rapidement découvrir des options de divertissement luxueuses et s'assurer que les invités de l'élite de Gotham vivent une expérience inoubliable. Cet outil l'aide à organiser l'événement parfait sur le thème des super-héros ! 🎉 ## Ressources - [Tutoriel sur les outils](https://huggingface.co/docs/smolagents/tutorials/tools) - Explorez ce tutoriel pour apprendre à travailler efficacement avec les outils. - [Documentation sur les outils](https://huggingface.co/docs/smolagents/v1.8.1/en/reference/tools) - Documentation de référence complète sur les outils. - [Visite guidée des outils](https://huggingface.co/docs/smolagents/v1.8.1/en/guided_tour#tools) - Une visite guidée étape par étape pour vous aider à construire et utiliser efficacement les outils. - [Construire des agents efficaces](https://huggingface.co/docs/smolagents/tutorials/building_good_agents) - Un guide détaillé sur les meilleures pratiques pour développer des agents de fonctions personnalisées fiables et performants. ================================================ FILE: units/fr/unit2/smolagents/vision_agents.mdx ================================================ # Agents visuel avec smolagents > [!WARNING] > Les exemples de cette section nécessitent l'accès à un modèle VLM puissant. Nous les avons testés en utilisant l'API GPT-4o. > Cependant, Pourquoi utiliser smolagents discute des solutions alternatives supportées par smolagents et Hugging Face. Si vous souhaitez explorer d'autres options, assurez-vous de consulter cette section. Doter les agents de capacités visuelles est crucial pour résoudre des tâches qui vont au-delà du traitement de texte. De nombreux défis du monde réel, comme la navigation web ou la compréhension de documents, nécessitent d'analyser un contenu visuel riche. Heureusement, `smolagents` fournit un support intégré pour les modèles de vision-langage (VLM), permettant aux agents de traiter et d'interpréter efficacement les images. Dans cet exemple, imaginez qu'Alfred soit chargé de vérifier les identités des invités assistant à la fête. Comme vous pouvez l'imaginer, Alfred pourrait ne pas être familier avec tout le monde. Pour l'aider, nous pouvons utiliser un agent qui vérifie leur identité en recherchant des informations visuelles sur leur apparence en utilisant un VLM. Cela permettra à Alfred de prendre des décisions éclairées sur qui peut entrer. Construisons cet exemple ! ## Fournir des images au début de l'exécution de l'agent > [!TIP] > Vous pouvez suivre le code dans ce notebook que vous pouvez exécuter avec Google Colab. Dans cette approche, les images sont transmises à l'agent au début et stockées comme `task_images` avec le *prompt* de tâche. L'agent traite ensuite ces images tout au long de son exécution. Considérez le cas où Alfred veut vérifier les identités des super-héros assistant à la fête. Il a déjà un jeu de données d'images de fêtes précédentes avec les noms des invités. Étant donné l'image d'un nouveau visiteur, l'agent peut la comparer avec le jeu de données existant et prendre une décision sur leur entrée. Dans ce cas, un invité essaie d'entrer, et Alfred soupçonne que ce visiteur pourrait être le Joker se faisant passer pour Wonder Woman. Alfred doit vérifier les identités pour empêcher quiconque d'indésirable d'entrer. Construisons l'exemple. D'abord, les images sont chargées. Dans ce cas, nous utilisons des images de Wikipédia pour garder l'exemple minimaliste, mais imaginez les cas d'usage possibles ! ```python from PIL import Image import requests from io import BytesIO image_urls = [ "https://upload.wikimedia.org/wikipedia/commons/e/e8/The_Joker_at_Wax_Museum_Plus.jpg", # Image du Joker "https://upload.wikimedia.org/wikipedia/en/9/98/Joker_%28DC_Comics_character%29.jpg" # Image du Joker ] images = [] for url in image_urls: headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" } response = requests.get(url,headers=headers) image = Image.open(BytesIO(response.content)).convert("RGB") images.append(image) ``` Maintenant que nous avons les images, l'agent nous dira si un invité est vraiment un super-héros (Wonder Woman) ou un méchant (le Joker). ```python from smolagents import CodeAgent, OpenAIServerModel model = OpenAIServerModel(model_id="gpt-4o") # Instancier l'agent agent = CodeAgent( tools=[], model=model, max_steps=20, verbosity_level=2 ) response = agent.run( """ Décrire le costume et le maquillage que porte le personnage de bande dessinée figurant sur ces photos et renvoyer la description. Indiquer si l'invité est le Joker ou Wonder Woman. """, images=images ) ``` Dans le cas de mon exécution, la sortie est la suivante, bien qu'elle puisse varier dans votre cas, comme nous l'avons déjà discuté : ```python { 'Costume et maquillage - Première image': ( 'Manteau violet et une cravate ou nœud papillon de soie violette sur une chemise jaune moutarde.', 'Peinture faciale blanche avec des traits exagérés, sourcils sombres, maquillage des yeux bleu, lèvres rouges formant un large sourire.' ), 'Costume et maquillage - Deuxième image': ( 'Costume sombre avec une fleur sur le revers, tenant une carte à jouer.', 'Peau pâle, cheveux verts, lèvres très rouges avec un sourire exagéré.' ), 'Identité du personnage': 'Ce personnage ressemble aux représentations connues du Joker des médias de bande dessinée.' } ``` Dans ce cas, la sortie révèle que la personne se fait passer pour quelqu'un d'autre, donc nous pouvons empêcher le Joker d'entrer à la fête ! ## Fournir des images avec recherche dynamique > [!TIP] > Vous pouvez suivre le code dans ce fichier Python L'approche précédente est précieuse et a de nombreux cas d'usage potentiels. Cependant, dans des situations où l'invité n'est pas dans la base de données, nous devons explorer d'autres façons de les identifier. Une solution possible est de récupérer dynamiquement des images et des informations à partir de sources externes, comme naviguer sur le web pour des détails. Dans cette approche, les images sont ajoutées dynamiquement à la mémoire de l'agent pendant l'exécution. Comme nous le savons, les agents dans `smolagents` sont basés sur la classe `MultiStepAgent`, qui est une abstraction du *framework ReAct*. Cette classe opère dans un cycle structuré où diverses variables et connaissances sont enregistrées à différentes étapes : 1. **SystemPromptStep :** Stocke le *prompt* système. 2. **TaskStep :** Enregistre la requête utilisateur et toute entrée fournie. 3. **ActionStep :** Capture les logs des actions de l'agent et les résultats. Cette approche structurée permet aux agents d'incorporer des informations visuelles dynamiquement et de répondre de manière adaptative aux tâches évolutives. Ci-dessous se trouve le diagramme que nous avons déjà vu, illustrant le processus de flux de travail dynamique et comment différentes étapes s'intègrent dans le cycle de vie de l'agent. Lors de la navigation, l'agent peut prendre des captures d'écran et les sauvegarder comme `observation_images` dans l'`ActionStep`. ![Récupération d'images dynamique](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/smolagents-can-see/diagram_adding_vlms_smolagents.png) Maintenant que nous comprenons le besoin, construisons notre exemple complet. Dans ce cas, Alfred veut un contrôle total sur le processus de vérification des invités, donc naviguer pour des détails devient une solution viable. Pour compléter cet exemple, nous avons besoin d'un nouvel ensemble d'outils pour l'agent. De plus, nous utiliserons Selenium et Helium, qui sont des outils d'automatisation de navigateur. Cela nous permettra de construire un agent qui explore le web, recherchant des détails sur un invité potentiel et récupérant des informations de vérification. Installons les outils nécessaires : ```bash pip install "smolagents[all]" helium selenium python-dotenv ``` Nous aurons besoin d'un ensemble d'outils d'agent spécifiquement conçus pour la navigation, tels que `search_item_ctrl_f`, `go_back` et `close_popups`. Ces outils permettent à l'agent d'agir comme une personne naviguant sur le web. ```python @tool def search_item_ctrl_f(text: str, nth_result: int = 1) -> str: """ Recherche du texte sur la page actuelle via Ctrl + F et saute à la nième occurrence. Args: text: Le texte à rechercher nth_result: Quelle occurrence aller (par défaut: 1) """ elements = driver.find_elements(By.XPATH, f"//*[contains(text(), '{text}')]") if nth_result > len(elements): raise Exception(f"Correspondance n°{nth_result} non trouvée (seulement {len(elements)} correspondances trouvées)") result = f"Trouvé {len(elements)} correspondances pour '{text}'." elem = elements[nth_result - 1] driver.execute_script("arguments[0].scrollIntoView(true);", elem) result += f"Focalisé sur l'élément {nth_result} de {len(elements)}" return result @tool def go_back() -> None: """Retourne à la page précédente.""" driver.back() @tool def close_popups() -> str: """ Ferme tout modal ou pop-up visible sur la page. Utilise ceci pour fermer les fenêtres pop-up ! Cela ne fonctionne pas sur les bannières de consentement de cookies. """ webdriver.ActionChains(driver).send_keys(Keys.ESCAPE).perform() ``` Nous avons également besoin de fonctionnalités pour sauvegarder des captures d'écran, car ce sera une partie essentielle de ce que notre agent *VLM* utilise pour accomplir la tâche. Cette fonctionnalité prend la capture d'écran et la sauvegarde dans `step_log.observations_images = [image.copy()]`, permettant à l'agent de stocker et traiter les images dynamiquement pendant qu'il navigue. ```python def save_screenshot(step_log: ActionStep, agent: CodeAgent) -> None: sleep(1.0) # Laisser les animations JavaScript se produire avant de prendre la capture d'écran driver = helium.get_driver() current_step = step_log.step_number if driver is not None: for step_logs in agent.logs: # Supprimer les captures d'écran précédentes des logs pour un traitement allégé if isinstance(step_log, ActionStep) and step_log.step_number <= current_step - 2: step_logs.observations_images = None png_bytes = driver.get_screenshot_as_png() image = Image.open(BytesIO(png_bytes)) print(f"Capture d'écran de navigateur capturée : {image.size} pixels") step_log.observations_images = [image.copy()] # Créer une copie pour s'assurer qu'elle persiste, important ! # Mettre à jour les observations avec l'URL actuelle url_info = f"URL actuelle : {driver.current_url}" step_log.observations = url_info if step_logs.observations is None else step_log.observations + "\n" + url_info return ``` Cette fonction est passée à l'agent comme `step_callback`, car elle est déclenchée à la fin de chaque étape pendant l'exécution de l'agent. Cela permet à l'agent de capturer et stocker dynamiquement des captures d'écran tout au long de son processus. Maintenant, nous pouvons générer notre agent de vision pour naviguer sur le web, en lui fournissant les outils que nous avons créés, avec le `DuckDuckGoSearchTool` pour explorer le web. Cet outil aidera l'agent à récupérer les informations nécessaires pour vérifier les identités des invités basées sur des indices visuels. ```python from smolagents import CodeAgent, OpenAIServerModel, DuckDuckGoSearchTool model = OpenAIServerModel(model_id="gpt-4o") agent = CodeAgent( tools=[DuckDuckGoSearchTool(), go_back, close_popups, search_item_ctrl_f], model=model, additional_authorized_imports=["helium"], step_callbacks=[save_screenshot], max_steps=20, verbosity_level=2, ) ``` Avec cela, Alfred est prêt à vérifier les identités des invités et prendre des décisions éclairées sur s'il faut les laisser entrer ou non à la fête : ```python agent.run(""" Je suis Alfred, le majordome du manoir Wayne, chargé de vérifier l'identité des invités à une fête. Une super-héroïne se présente à l'entrée en prétendant être Wonder Woman, mais je dois vérifier si elle est bien celle qu'elle prétend être. Veuillez rechercher des images de Wonder Woman et générer une description visuelle détaillée à partir de ces images. De plus, naviguez sur Wikipédia pour recueillir des détails clés sur son apparence. Grâce à ces informations, je pourrai déterminer s'il convient de lui accorder l'accès à l'événement. """ + helium_instructions) ``` Vous pouvez voir que nous incluons `helium_instructions` dans le cadre de la tâche. Ce *prompt* spécial vise à contrôler la navigation de l'agent, s'assurant qu'il suit les bonnes étapes lors de la navigation web. Voyons comment cela fonctionne dans la vidéo ci-dessous : C'est la sortie finale : ```python Réponse finale : Wonder Woman est typiquement représentée portant un bustier rouge et or, un short ou une jupe bleu avec des étoiles blanches, un tiare doré, des bracelets argentés et un lasso de vérité doré. Elle est la Princesse Diana de Themyscira, connue sous le nom de Diana Prince dans le monde des hommes. ``` Avec tout cela, nous avons créé avec succès notre vérificateur d'identité pour la fête ! Alfred a maintenant les outils nécessaires pour s'assurer que seuls les bons invités franchissent la porte. Tout est prêt pour passer du bon temps au manoir Wayne ! ## Lectures complémentaires - [Nous venons de donner la vue à smolagents](https://huggingface.co/blog/smolagents-can-see) - Blog décrivant la fonctionnalité d'agent visuel. - [Automatisation de navigateur web avec agents 🤖🌐](https://huggingface.co/docs/smolagents/examples/web_browser) - Exemple pour la navigation web utilisant un agent visuel. - [Exemple d'agent visuel pour navigateur web](https://github.com/huggingface/smolagents/blob/main/src/smolagents/vision_web_browser.py) - Exemple pour la navigation web utilisant un agent visuel. ================================================ FILE: units/fr/unit2/smolagents/why_use_smolagents.mdx ================================================ ![smolagents banner](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/smolagents/license_to_call.png) # Pourquoi utiliser smolagents Dans ce module, nous explorerons les avantages et les inconvénients de l'utilisation de [smolagents](https://huggingface.co/docs/smolagents/en/index), vous aidant à prendre une décision éclairée pour savoir si c'est le bon *framework* pour vos besoins. ## Qu'est-ce que `smolagents` ? `smolagents` est un *framework* simple mais puissant pour construire des agents. Il fournit aux LLM la capacité d'agir (_agency_) pour interagir avec le monde réel, comme effectuer des recherches ou générer des images. Comme nous l'avons appris dans l'Unité 1, les agents sont des programmes qui utilisent des LLM pour générer des **raisonnements** basés sur des **observations** afin d'effectuer des **actions**. Explorons comment cela est implémenté dans *smolagents*. ### Principaux avantages de `smolagents` - **Simplicité :** Complexité de code et abstractions minimales, pour rendre le *framework* facile à comprendre, adopter et étendre - **Support LLM flexible :** Fonctionne avec n'importe quel LLM grâce à l'intégration avec les outils Hugging Face et les API externes - **Approche orientée code :** Support de première classe pour les *agents à code* qui écrivent leurs actions directement en code, éliminant le besoin d'analyse syntaxique et simplifiant l'appel d'outils - **Intégration au Hub d'Hugging Face :** Intégration transparente avec le Hub, permettant l'utilisation de *Spaces* Gradio comme outils ### Quand utiliser smolagents ? Avec ces avantages en tête, quand devrions-nous utiliser *smolagents* plutôt que d'autres *frameworks* ? *smolagents* est idéal quand : - Vous avez besoin d'une **solution légère et minimale.** - Vous voulez **expérimenter rapidement** sans configurations complexes. - Votre **logique d'application est simple.** ### Actions via code vs. via JSON Contrairement à d'autres *frameworks* où les agents écrivent des actions en JSON, `smolagents` **se concentre sur les appels d'outils en code**, simplifiant le processus d'exécution. C'est parce qu'il n'y a pas besoin d'analyser le JSON pour construire du code qui appelle les outils : la sortie peut être exécutée directement. Le diagramme suivant illustre cette différence : ![Code vs. JSON actions](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/code_vs_json_actions.png) Pour revoir la différence entre les actions via code vs. via JSON, vous pouvez revisiter [la section Actions dans l'Unité 1](https://huggingface.co/learn/agents-course/unit1/actions#actions-enabling-the-agent-to-engage-with-its-environment). ### Types d'agents dans `smolagents` Les agents dans `smolagents` fonctionnent comme des **agents multi-étapes**. Chaque [`MultiStepAgent`](https://huggingface.co/docs/smolagents/main/en/reference/agents#smolagents.MultiStepAgent) effectue : - Un raisonnement - Un appel et une exécution d'outil En plus d'utiliser **[CodeAgent](https://huggingface.co/docs/smolagents/main/en/reference/agents#smolagents.CodeAgent)** comme type principal d'agent, *smolagents* supporte également **[ToolCallingAgent](https://huggingface.co/docs/smolagents/main/en/reference/agents#smolagents.ToolCallingAgent)**, qui écrit des appels d'outils en JSON. Nous explorerons chaque type d'agent plus en détail dans les sections suivantes. > [!TIP] > Dans smolagents, les outils sont définis en utilisant le décorateur @tool enveloppant une fonction Python ou la classe Tool. ### Intégration de modèles dans `smolagents` `smolagents` supporte une intégration flexible des LLM, vous permettant d'utiliser n'importe quel modèle appelable qui répond à [certains critères](https://huggingface.co/docs/smolagents/main/en/reference/models). Le *framework* fournit plusieurs classes prédéfinies pour simplifier les connexions aux modèles : - **[TransformersModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.TransformersModel) :** Implémente un pipeline `transformers` local pour une intégration transparente. - **[InferenceClientModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.InferenceClientModel) :** Supporte les appels d'[inférence serverless](https://huggingface.co/docs/huggingface_hub/main/en/guides/inference) via [l'infrastructure d'Hugging Face](https://huggingface.co/docs/api-inference/index), ou via un nombre croissant de [fournisseurs d'inférence tiers](https://huggingface.co/docs/huggingface_hub/main/en/guides/inference#supported-providers-and-tasks). - **[LiteLLMModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.LiteLLMModel) :** Tire parti de [LiteLLM](https://www.litellm.ai/) pour des interactions légères avec les modèles. - **[OpenAIServerModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.OpenAIServerModel) :** Se connecte à tout service offrant une interface API OpenAI. - **[AzureOpenAIServerModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.AzureOpenAIServerModel) :** Supporte l'intégration avec tout déploiement Azure OpenAI. Cette flexibilité garantit que les développeurs peuvent choisir le modèle et le service les plus adaptés à leurs cas d'usage spécifiques, et permet une expérimentation facile. Maintenant que nous avons compris pourquoi et quand utiliser *smolagents*, plongeons plus profondément dans cette puissante bibliothèque ! ## Ressources - [Blog smolagents](https://huggingface.co/blog/smolagents) - Introduction à smolagents et aux interactions par code ================================================ FILE: units/fr/unit3/README.md ================================================ ================================================ FILE: units/fr/unit3/agentic-rag/agent.mdx ================================================ # Création de l'agent pour le gala Maintenant que nous avons construit tous les composants nécessaires pour Alfred, il est temps de tout rassembler en un agent complet qui peut aider à organiser notre gala. Dans cette section, nous allons combiner les outils de récupération d'informations sur les invités, de recherche web, d'informations météorologiques et de statistiques du Hub en un seul agent puissant. ## Assemblage d'Alfred : l'agent complet Au lieu de réimplémenter tous les outils que nous avons créés dans les sections précédentes, nous les importerons à partir de leurs modules respectifs que nous avons sauvegardés dans les fichiers `tools.py` et `retriever.py`. > [!TIP] > Si vous n'avez pas encore implémenté les outils, retournez aux sections outils et récupérateur pour les implémenter, et ajoutez-les aux fichiers tools.py et retriever.py. Importons les bibliothèques nécessaires et les outils des sections précédentes : ```python # Importer les bibliothèques nécessaires import random from smolagents import CodeAgent, InferenceClientModel # Importer nos outils personnalisés de leurs modules from tools import DuckDuckGoSearchTool, WeatherInfoTool, HubStatsTool from retriever import load_guest_dataset ``` Maintenant, combinons tous ces outils en un seul agent : ```python # Initialiser le modèle Hugging Face model = InferenceClientModel() # Initialiser l'outil de recherche web search_tool = DuckDuckGoSearchTool() # Initialiser l'outil météorologique weather_info_tool = WeatherInfoTool() # Initialiser l'outil de statistiques Hub hub_stats_tool = HubStatsTool() # Charger le jeu de données des invités et initialiser l'outil d'informations sur les invités guest_info_tool = load_guest_dataset() # Créer Alfred avec tous les outils alfred = CodeAgent( tools=[guest_info_tool, weather_info_tool, hub_stats_tool, search_tool], model=model, add_base_tools=True, # Ajouter tous les outils de base supplémentaires planning_interval=3 # Activer la planification toutes les 3 étapes ) ``` ```python # Importer les bibliothèques nécessaires from llama_index.core.agent.workflow import AgentWorkflow from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI from tools import search_tool, weather_info_tool, hub_stats_tool from retriever import guest_info_tool ``` Maintenant, combinons tous ces outils en un seul agent : ```python # Initialiser le modèle Hugging Face llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") # Créer Alfred avec tous les outils alfred = AgentWorkflow.from_tools_or_functions( [guest_info_tool, search_tool, weather_info_tool, hub_stats_tool], llm=llm, ) ``` ```python from typing import TypedDict, Annotated from langgraph.graph.message import add_messages from langchain_core.messages import AnyMessage, HumanMessage, AIMessage from langgraph.prebuilt import ToolNode from langgraph.graph import START, StateGraph from langgraph.prebuilt import tools_condition from langchain_huggingface import HuggingFaceEndpoint, ChatHuggingFace from tools import DuckDuckGoSearchRun, weather_info_tool, hub_stats_tool from retriever import guest_info_tool ``` Maintenant, combinons tous ces outils en un seul agent : ```python # Initialiser l'outil de recherche web search_tool = DuckDuckGoSearchRun() # Générer l'interface de chat, incluant les outils llm = HuggingFaceEndpoint( repo_id="Qwen/Qwen2.5-Coder-32B-Instruct", huggingfacehub_api_token=HUGGINGFACEHUB_API_TOKEN, ) chat = ChatHuggingFace(llm=llm, verbose=True) tools = [guest_info_tool, search_tool, weather_info_tool, hub_stats_tool] chat_with_tools = chat.bind_tools(tools) # Générer l'AgentState et le graphe d'agent class AgentState(TypedDict): messages: Annotated[list[AnyMessage], add_messages] def assistant(state: AgentState): return { "messages": [chat_with_tools.invoke(state["messages"])], } ## Le graphe builder = StateGraph(AgentState) # Définir les nœuds : ils font le travail builder.add_node("assistant", assistant) builder.add_node("tools", ToolNode(tools)) # Définir les arêtes : elles déterminent comment le flux de contrôle se déplace builder.add_edge(START, "assistant") builder.add_conditional_edges( "assistant", # Si le dernier message nécessite un outil, router vers les outils # Sinon, fournir une réponse directe tools_condition, ) builder.add_edge("tools", "assistant") alfred = builder.compile() ``` Votre agent est maintenant prêt à être utilisé ! ## Utilisation d'Alfred : exemples de bout en bout Maintenant qu'Alfred est entièrement équipé de tous les outils nécessaires, voyons comment il peut aider avec diverses tâches pendant le gala. ### Exemple 1 : trouver des informations sur les invités Voyons comment Alfred peut nous aider avec nos informations sur les invités. ```python query = "Parle-moi de Lady Ada Lovelace" response = alfred.run(query) print("🎩 Réponse d'Alfred :") print(response) ``` Sortie attendue : ``` 🎩 Réponse d'Alfred : Basé sur les informations que j'ai récupérées, Lady Ada Lovelace est une mathématicienne estimée et une amie. Elle est renommée pour son travail pionnier en mathématiques et en informatique, souvent célébrée comme la première programmeuse informatique en raison de son travail sur la machine analytique de Charles Babbage. Son adresse email est ada.lovelace@example.com. ``` ```python query = "Parle-moi de Lady Ada Lovelace. Quel est son parcours ?" response = await alfred.run(query) print("🎩 Réponse d'Alfred :") print(response.response.blocks[0].text) ``` Sortie attendue : ``` 🎩 Réponse d'Alfred : Lady Ada Lovelace était une mathématicienne et écrivaine anglaise, mieux connue pour son travail sur la machine analytique de Charles Babbage. Elle a été la première à reconnaître que la machine avait des applications au-delà du calcul pur. ``` ```python response = alfred.invoke({"messages": "Parle-moi de Lady Ada Lovelace"}) print("🎩 Réponse d'Alfred :") print(response['messages'][-1].content) ``` Sortie attendue : ``` 🎩 Réponse d'Alfred : Ada Lovelace, aussi connue sous le nom d'Augusta Ada King, Comtesse de Lovelace, était une mathématicienne et écrivaine anglaise. Née le 10 décembre 1815 et décédée le 27 novembre 1852, elle est renommée pour son travail sur la machine analytique de Charles Babbage, un ordinateur mécanique à usage général proposé. Ada Lovelace est célébrée comme l'une des premières programmeuses informatiques parce qu'elle a créé un programme pour la machine analytique en 1843. Elle a reconnu que la machine pourrait être utilisée pour plus que de simples calculs, envisageant son potentiel d'une manière que peu de gens faisaient à l'époque. Ses contributions au domaine de l'informatique ont posé les bases pour les développements futurs. Une journée en octobre, désignée comme le jour d'Ada Lovelace, honore les contributions des femmes à la science et à la technologie, inspirée par le travail pionnier de Lovelace. ``` ### Exemple 2 : Vérifier la météo pour le feu d'artifice Voyons comment Alfred peut nous aider avec la météo. ```python query = "Quel temps fait-il à Paris ce soir ? Sera-t-il approprié pour notre spectacle pyrotechnique ?" response = alfred.run(query) print("🎩 Réponse d'Alfred :") print(response) ``` Sortie attendue (variera en raison du caractère aléatoire) : ``` 🎩 Réponse d'Alfred : J'ai vérifié la météo à Paris pour vous. Actuellement, il fait clair avec une température de 25°C. Ces conditions sont parfaites pour le spectacle de feux d'artifice ce soir. Le ciel clair offrira une excellente visibilité pour le spectacle spectaculaire, et la température confortable s'assurera que les invités peuvent profiter de l'événement en plein air sans inconfort. ``` ```python query = "Quel temps fait-il à Paris ce soir ? Sera-t-il approprié pour notre spectacle pyrotechnique ?" response = await alfred.run(query) print("🎩 Réponse d'Alfred :") print(response) ``` Sortie attendue : ``` 🎩 Réponse d'Alfred : La météo à Paris ce soir est pluvieuse avec une température de 15°C. Étant donné la pluie, il se peut que ce ne soit pas approprié pour un spectacle pyrotechnique. ``` ```python response = alfred.invoke({"messages": "Quel temps fait-il à Paris ce soir ? Sera-t-il approprié pour notre spectacle pyrotechnique ?"}) print("🎩 Réponse d'Alfred :") print(response['messages'][-1].content) ``` Sortie attendue : ``` 🎩 Réponse d'Alfred : La météo à Paris ce soir est pluvieuse avec une température de 15°C, ce qui peut ne pas être approprié pour votre spectacle pyrotechnique. ``` ### Exemple 3 : impressionner les chercheurs en IA Voyons comment Alfred peut nous aider à impressionner les chercheurs en IA. ```python query = "Un de nos invités vient de Qwen. Que peux-tu me dire sur leur modèle le plus populaire ?" response = alfred.run(query) print("🎩 Réponse d'Alfred :") print(response) ``` Sortie attendue : ``` 🎩 Réponse d'Alfred : Le modèle Qwen le plus populaire est Qwen/Qwen2.5-VL-7B-Instruct avec 3 313 345 téléchargements. ``` ```python query = "Un de nos invités vient de Google. Que peux-tu me dire sur leur modèle le plus populaire ?" response = await alfred.run(query) print("🎩 Réponse d'Alfred :") print(response) ``` Sortie attendue : ``` 🎩 Réponse d'Alfred : Le modèle le plus populaire par Google sur le Hugging Face Hub est google/electra-base-discriminator, avec 28 546 752 téléchargements. ``` ```python response = alfred.invoke({"messages": "Un de nos invités vient de Qwen. Que peux-tu me dire sur leur modèle le plus populaire ?"}) print("🎩 Réponse d'Alfred :") print(response['messages'][-1].content) ``` Sortie attendue : ``` 🎩 Réponse d'Alfred : Le modèle le plus téléchargé par Qwen est Qwen/Qwen2.5-VL-7B-Instruct avec 3 313 345 téléchargements. ``` ### Exemple 4 : combiner plusieurs outils Voyons comment Alfred peut nous aider à préparer une conversation avec le Dr. Nikola Tesla. ```python query = "J'ai besoin de parler avec le Dr. Nikola Tesla des avancées récentes en énergie sans fil. Peux-tu m'aider à préparer cette conversation ?" response = alfred.run(query) print("🎩 Réponse d'Alfred :") print(response) ``` Sortie attendue : ``` 🎩 Réponse d'Alfred : J'ai rassemblé des informations pour vous aider à préparer votre conversation avec le Dr. Nikola Tesla. Informations sur l'invité : Nom : Dr. Nikola Tesla Relation : vieil ami de la période à l'université Description : Le Dr. Nikola Tesla est un vieil ami de votre période à l'université. Il vient récemment de breveter un nouveau système de transmission d'énergie sans fil et serait ravi d'en discuter avec vous. N'oubliez pas qu'il est passionné par les pigeons, donc cela pourrait faire une bonne conversation. Email : nikola.tesla@gmail.com Avancées récentes en énergie sans fil : Basé sur ma recherche web, voici quelques développements récents en transmission d'énergie sans fil : 1. Les chercheurs ont fait des progrès dans la transmission d'énergie sans fil à longue portée utilisant des ondes électromagnétiques focalisées 2. Plusieurs entreprises développent des technologies de couplage inductif résonnant pour l'électronique grand public 3. Il y a de nouvelles applications dans la recharge de véhicules électriques sans connexions physiques Amorces de conversation : 1. "J'adorerais entendre parler de votre nouveau brevet sur la transmission d'énergie sans fil. Comment se compare-t-il à vos concepts originaux de votre période à l'université ?" 2. "Avez-vous vu les développements récents en couplage inductif résonnant pour l'électronique grand public ? Que pensez-vous de leur approche ?" 3. "Comment vont vos pigeons ? Je me souviens de votre fascination pour eux." Cela devrait vous donner de quoi discuter avec le Dr. Tesla tout en démontrant votre connaissance de ses intérêts et des développements récents dans son domaine. ``` ```python query = "J'ai besoin de parler avec le Dr. Nikola Tesla des avancées récentes en énergie sans fil. Peux-tu m'aider à préparer cette conversation ?" response = await alfred.run(query) print("🎩 Réponse d'Alfred :") print(response) ``` Sortie attendue : ``` 🎩 Réponse d'Alfred : Voici quelques avancées récentes en énergie sans fil que vous pourriez trouver utiles pour votre conversation avec le Dr. Nikola Tesla : 1. **Avancées et défis dans le transfert d'énergie sans fil** : Cet article discute de l'évolution du transfert d'énergie sans fil (WPT) des méthodes filaires conventionnelles aux applications modernes, y compris les stations d'énergie solaire spatiales. Il souligne l'accent initial sur la technologie des micro-ondes et la demande actuelle pour le WPT en raison de la montée des appareils électriques. 2. **Avancées récentes dans les technologies de transfert d'énergie sans fil pour l'électronique interfacée au corps** : Cet article explore le transfert d'énergie sans fil (WET) comme solution pour alimenter l'électronique interfacée au corps sans avoir besoin de batteries ou de fils de plomb. Il discute des avantages et des applications potentielles du WET dans ce contexte. 3. **Transfert d'énergie sans fil et récolte d'énergie : Statut actuel et tendances futures** : Cet article fournit un aperçu des avancées récentes dans les méthodes d'alimentation sans fil, y compris la récolte d'énergie et le transfert d'énergie sans fil. Il présente plusieurs applications prometteuses et discute des tendances futures dans le domaine. 4. **Transfert d'énergie sans fil : Applications, défis, barrières, et les ``` ```python response = alfred.invoke({"messages":"J'ai besoin de parler avec le 'Dr. Nikola Tesla' des avancées récentes en énergie sans fil. Peux-tu m'aider à préparer cette conversation ?"}) print("🎩 Réponse d'Alfred :") print(response['messages'][-1].content) ``` Sortie attendue : ``` Basé sur les informations fournies, voici les points clés pour préparer la conversation avec le 'Dr. Nikola Tesla' sur les avancées récentes en énergie sans fil :\n1. **Transmission d'énergie sans fil (WPT) :** Discutez de la façon dont le WPT révolutionne le transfert d'énergie en éliminant le besoin de cordons et en exploitant des mécanismes comme le couplage inductif et résonnant.\n2. **Avancées dans la recharge sans fil :** Mettez en évidence les améliorations en efficacité, les vitesses de recharge plus rapides, et la montée des solutions de recharge sans fil certifiées Qi/Qi2.\n3. **Innovations 5G-Advanced et protocole sans fil NearLink :** Mentionnez-les comme des développements qui améliorent la vitesse, la sécurité et l'efficacité dans les réseaux sans fil, qui peuvent soutenir les technologies d'énergie sans fil avancées.\n4. **IA et ML à la périphérie :** Parlez de la façon dont l'IA et l'apprentissage automatique s'appuieront sur les réseaux sans fil pour apporter l'intelligence à la périphérie, améliorant l'automatisation et l'intelligence dans les maisons et bâtiments intelligents.\n5. **Matter, Thread, et avancées de sécurité :** Discutez de ceux-ci comme des innovations clés qui pilotent la connectivité, l'efficacité et la sécurité dans les appareils et systèmes IoT.\n6. **Percées dans la technologie de recharge sans fil :** Incluez toute percée récente ou études, comme celle de l'Université nationale d'Incheon, pour justifier les avancées dans la recharge sans fil. ``` ## Fonctionnalités avancées : une mémoire de la conversation Pour rendre Alfred encore plus utile pendant le gala, nous pouvons activer une mémoire de la conversation pour qu'il se souvienne des interactions précédentes : ```python # Créer Alfred avec une mémoire de la conversation alfred_with_memory = CodeAgent( tools=[guest_info_tool, weather_info_tool, hub_stats_tool, search_tool], model=model, add_base_tools=True, planning_interval=3 ) # Première interaction response1 = alfred_with_memory.run("Parle-moi de Lady Ada Lovelace.") print("🎩 Première réponse d'Alfred :") print(response1) # Deuxième interaction (faisant référence à la première) response2 = alfred_with_memory.run("Sur quels projets travaille-t-elle actuellement ?", reset=False) print("🎩 Deuxième réponse d'Alfred :") print(response2) ``` ```python from llama_index.core.workflow import Context alfred = AgentWorkflow.from_tools_or_functions( [guest_info_tool, search_tool, weather_info_tool, hub_stats_tool], llm=llm ) # Mémoriser l'état ctx = Context(alfred) # Première interaction response1 = await alfred.run("Parle-moi de Lady Ada Lovelace.", ctx=ctx) print("🎩 Première réponse d'Alfred :") print(response1) # Deuxième interaction (faisant référence à la première) response2 = await alfred.run("Sur quels projets travaille-t-elle actuellement ?", ctx=ctx) print("🎩 Deuxième réponse d'Alfred :") print(response2) ``` ```python # Première interaction response = alfred.invoke({"messages": [HumanMessage(content="Parle-moi de 'Lady Ada Lovelace'. Quel est son parcours et comment est-elle liée à moi ?")]}) print("🎩 Réponse d'Alfred :") print(response['messages'][-1].content) print() # Deuxième interaction (faisant référence à la première) response = alfred.invoke({"messages": response["messages"] + [HumanMessage(content="Sur quels projets travaille-t-elle actuellement ?")]}) print("🎩 Réponse d'Alfred :") print(response['messages'][-1].content) ``` Remarquez qu'aucune de ces trois approches ne couple directement la mémoire avec l'agent. Y a-t-il une raison spécifique pour ce choix de conception 🧐 ? * smolagents : La mémoire n'est pas préservée entre différentes exécutions, vous devez explicitement la déclarer en utilisant `reset=False`. * LlamaIndex : Nécessite d'ajouter explicitement un objet de contexte pour la gestion de la mémoire au sein d'une exécution. * LangGraph : Offre des options pour récupérer les messages précédents ou utiliser un composant [MemorySaver](https://langchain-ai.github.io/langgraph/tutorials/introduction/#part-3-adding-memory-to-the-chatbot) dédié. ## Conclusion Félicitations ! Vous avez réussi à construire Alfred, un agent sophistiqué équipé de plusieurs outils pour aider à organiser le gala le plus extravagant du siècle. Il peut maintenant : 1. Récupérer des informations détaillées sur les invités 2. Vérifier les conditions météorologiques pour planifier les activités en plein air 3. Fournir des informations sur les constructeurs d'IA influents et leurs modèles 4. Rechercher sur le web les dernières informations 5. Maintenir le contexte de conversation avec la mémoire Avec ces capacités, Alfred est prêt à s'assurer que votre gala soit un succès retentissant, impressionnant les invités avec une attention personnalisée et des informations à jour. ================================================ FILE: units/fr/unit3/agentic-rag/agentic-rag.mdx ================================================ # RAG agentique Dans cette unité, nous allons examiner comment nous pouvons utiliser le *RAG agentique* pour aider Alfred à préparer l'incroyable gala. > [!TIP] > Nous avons déjà discuté du RAG et du RAG agentique dans l'unité précédente, donc n'hésitez pas à passer directement à la suite si vous êtes déjà familier avec ces concepts. Les LLM sont entraînés sur d'énormes corpus de données pour apprendre des connaissances générales. Cependant, ce modèle de connaissance du monde peut ne pas toujours être des informations pertinentes et à jour. **Le RAG résout ce problème en trouvant et récupérant des informations pertinentes à partir de vos données et en les transmettant au LLM.** ![RAG](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/rag.png) Maintenant, pensez à comment Alfred fonctionne : 1. Nous lui avons demandé d'aider à planifier un gala 2. Il doit trouver les dernières nouvelles et informations météorologiques 3. Il doit structurer et rechercher les informations sur les invités Tout comme Alfred a besoin de chercher dans vos informations domestiques pour être utile, tout agent a besoin d'un moyen de trouver et comprendre les données pertinentes. **Le RAG agentique est un moyen puissant d'utiliser les agents pour répondre aux questions sur vos données.** Nous pouvons passer divers outils à Alfred pour l'aider à répondre aux questions. Cependant, au lieu de répondre automatiquement à la question sur la base de documents, Alfred peut décider d'utiliser tout autre outil ou flux pour répondre à la question. ![RAG agentique](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/agentic-rag.png) Commençons **à construire notre *workflow* de RAG agentique !** Tout d'abord, nous allons créer un outil de RAG pour récupérer les détails à jour sur les invités. Ensuite, nous développerons des outils pour la recherche web, les mises à jour météorologiques et les statistiques de téléchargement de modèles sur le Hub d'Hugging Face. Enfin, nous intégrerons le tout pour donner vie à notre agent de RAG agentique ! ================================================ FILE: units/fr/unit3/agentic-rag/conclusion.mdx ================================================ # Conclusion Dans cette unité, nous avons appris comment créer un système de RAG agentique pour aider Alfred, notre sympathique agent, à préparer et gérer un gala exceptionnel. La combinaison du RAG avec les capacités agentiques démontre à quel point les assistants IA peuvent devenir puissants quand ils ont : - Accès à de la connaissance structurée (informations sur les invités) - La capacité de récupérer des informations en temps réel (recherche web) - Accès à des outils spécifiques au domaine (informations météorologiques, statistiques du Hub) - Une mémoire des interactions passées Avec ces capacités, Alfred est maintenant bien équipé pour être l'hôte parfait, capable de répondre aux questions sur les invités, fournir des informations à jour, et s'assurer que le gala se déroule sans encombre—gérant même le timing parfait pour le spectacle pyrotechnique ! > [!TIP] > Maintenant que vous avez construit un agent complet, vous pourriez vouloir : > > - Créer des outils plus spécialisés pour vos propres cas d'usage > - Implémenter des systèmes de RAG plus sophistiqués avec des embeddings > - Construire des systèmes multi-agents où les agents peuvent collaborer > - Déployer votre agent comme un service avec lequel d'autres peuvent interagir ================================================ FILE: units/fr/unit3/agentic-rag/introduction.mdx ================================================ # Introduction au cas d'usage sur la RAG agentique ![Bannière RAG agentique](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit3/agentic-rag/thumbnail.jpg) Dans cette unité, nous aiderons Alfred, notre sympathique agent qui organise le gala, en utilisant le RAG agentique pour créer un outil qui peut être utilisé pour répondre aux questions sur les invités du gala. > [!TIP] > Il s'agit d'un cas d'usage concret pour le RAG agentique, que vous pourriez utiliser pour vos propres projets ou à votre travail. Si vous souhaitez tirer davantage parti de ce projet, pourquoi ne pas l'essayer sur votre propre cas d'usage et partager sur Discord ? Vous pouvez choisir n'importe lequel des *frameworks* abordés dans le cours pour ce cas d'usage. Nous fournissons des exemples de code pour chacun dans des onglets séparés. ## Un gala mémorable Maintenant, il est temps de se salir les mains avec un vrai cas d'usage. Plantons le décor ! **Vous avez décidé d'organiser la fête la plus extravagante et opulente du siècle.** Cela signifie des festins somptueux, des danseurs enchanteurs, des DJ renommés, des boissons exquises, un spectacle de feux d'artifice époustouflant, et bien plus encore. Alfred, votre agent, se prépare à veiller sur tous vos besoins pour cette fête, et **il va tout gérer lui-même**. Pour ce faire, il doit avoir accès à toutes les informations sur la fête, y compris le menu, les invités, le programme, les prévisions météorologiques, etc. Non seulement cela, mais il doit aussi s'assurer que la fête va être un succès, donc **il doit être capable de répondre à toutes les questions sur la fête pendant celle-ci**, tout en gérant les situations imprévues qui peuvent survenir. Alfred ne peut pas le faire seul, donc nous devons nous assurer qu'il a accès à toutes les informations et outils dont il a besoin. Tout d'abord, donnons-lui une liste d'exigences strictes pour le gala. ## Les exigences du gala Une personne correctement éduquée de l'époque de la **Renaissance** devait avoir trois traits principaux. Elle devait avoir une connaissance approfondie en **sport, culture et science**. Donc, nous devons nous assurer que nous pouvons impressionner nos invités avec notre connaissance et leur offrir un gala vraiment inoubliable. Cependant, pour éviter tout conflit, il y a **certains sujets, comme la politique et la religion, qui doivent être évités lors d'un gala.** Il doit s'agir d'une fête amusante sans conflits liés aux croyances et aux idéaux. Selon l'étiquette, **un bon hôte doit connaître les antécédents des invités**, y compris leurs centres d'intérêt et leurs activités. Un bon hôte fait aussi des commérages et partage des histoires sur les invités les uns avec les autres. Enfin, nous devons nous assurer que nous avons **des connaissances générales sur la météo** afin de pouvoir trouver en permanence une mise à jour en temps réel pour garantir un timing parfait pour le lancement du feu d'artifice pour terminer le gala en beauté ! 🎆 Comme vous pouvez le voir, Alfred a besoin de beaucoup d'informations pour organiser le gala. Heureusement, nous pouvons l'aider et le préparer en lui donnant un entraînement en ***Retrieval Augmented Generation* (RAG) !** Commençons par créer les outils dont Alfred a besoin pour pouvoir organiser le gala ! ================================================ FILE: units/fr/unit3/agentic-rag/invitees.mdx ================================================ # Création d'un RAG pour converser avec les invités Alfred, votre agent de confiance, se prépare pour le gala le plus extravagant du siècle. Pour s'assurer que l'événement se déroule sans encombre, il a besoin d'un accès rapide à des informations à jour sur chaque invité. Aidons le en créant un outil RAG alimenté par notre jeu de données personnalisé. ## Pourquoi un RAG pour un gala ? Imaginez Alfred se mêlant aux invités, ayant besoin de se rappeler des détails spécifiques sur chaque personne à tout moment. Un LLM traditionnel pourrait avoir du mal avec cette tâche parce que : 1. La liste des invités est spécifique à votre événement et ne fait pas partie des données d'entraînement du modèle 2. Les informations sur les invités peuvent changer ou être mises à jour fréquemment 3. Alfred doit récupérer des détails précis comme les adresses email C'est là que le RAG brille ! En combinant un système de récupération avec un LLM, Alfred peut accéder à des informations précises et à jour sur vos invités à la demande. > [!TIP] > Vous pouvez choisir n'importe lequel des frameworks couverts dans le cours pour ce cas d'usage. Sélectionnez votre option préférée dans les onglets de code. ## Configuration de notre application Dans cette unité, nous développerons notre agent au sein d'un *Space*, sous la forme d'un projet Python structuré. Cette approche nous aide à maintenir un code propre et modulaire en organisant différentes fonctionnalités dans des fichiers séparés. De plus, cela permet un cas d'usage plus réaliste où vous déploieriez l'application pour une utilisation publique. ### Structure du projet - **`tools.py`** – Fournit des outils auxiliaires pour l'agent. - **`retriever.py`** – Implémente les fonctions de récupération pour soutenir l'accès à la connaissance. - **`app.py`** – Intègre tous les composants dans un agent entièrement fonctionnel, que nous finaliserons dans la dernière partie de cette unité. Pour une référence pratique, consultez [ce *Space*](https://huggingface.co/spaces/agents-course/Unit_3_Agentic_RAG) sur un RAG agentique. N'hésitez pas à le cloner et à expérimenter ! Vous pouvez tester directement l'agent ci-dessous : ## Aperçu du jeu de données Notre jeu de données [`agents-course/unit3-invitees`](https://huggingface.co/datasets/agents-course/unit3-invitees/) contient les champs suivants pour chaque invité : - **Name** : Nom complet de l'invité - **Relation** : Comment l'invité est lié à l'hôte - **Description** : Une brève biographie ou des faits intéressants sur l'invité - **Email Address** : Informations de contact pour envoyer des invitations ou des suivis Voici un aperçu du jeu de données : > [!TIP] > Dans un scénario réel, ce jeu de données pourrait être étendu pour inclure les préférences alimentaires, les intérêts pour les cadeaux, les sujets de conversation à éviter, et d'autres détails utiles pour un hôte. ## Construction d'un outil pour un livre d'or Nous allons créer un outil personnalisé qu'Alfred peut utiliser pour récupérer rapidement les informations sur les invités pendant le gala. Décomposons cela en trois étapes gérables : 1. Charger et préparer le jeu de données 2. Créer l'outil de récupération 3. Intégrer l'outil à Alfred Commençons par charger et préparer le jeu de données ! ### Étape 1 : Charger et préparer le jeu de données Tout d'abord, nous devons transformer nos données brutes sur les invités en un format optimisé pour la récupération. Nous utiliserons la bibliothèque `datasets` d'Hugging Face pour charger le jeu de données et le convertir en une liste d'objets `Document` du module `langchain.docstore.document`. ```python import datasets from langchain_core.documents import Document # Charger le jeu de données guest_dataset = datasets.load_dataset("agents-course/unit3-invitees", split="train") # Convertir les entrées du jeu de données en objets Document docs = [ Document( page_content="\n".join([ f"Name: {guest['name']}", f"Relation: {guest['relation']}", f"Description: {guest['description']}", f"Email: {guest['email']}" ]), metadata={"name": guest["name"]} ) for guest in guest_dataset ] ``` Nous utiliserons la bibliothèque `datasets` d'Hugging Face pour charger le jeu de données et le convertir en une liste d'objets `Document` du module `llama_index.core.schema`. ```python import datasets from llama_index.core.schema import Document # Charger le jeu de données guest_dataset = datasets.load_dataset("agents-course/unit3-invitees", split="train") # Convertir les entrées du jeu de données en objets Document docs = [ Document( text="\n".join([ f"Name: {guest_dataset['name'][i]}", f"Relation: {guest_dataset['relation'][i]}", f"Description: {guest_dataset['description'][i]}", f"Email: {guest_dataset['email'][i]}" ]), metadata={"name": guest_dataset['name'][i]} ) for i in range(len(guest_dataset)) ] ``` Nous utiliserons la bibliothèque `datasets` d'Hugging Face pour charger le jeu de données et le convertir en une liste d'objets `Document` du module `langchain.docstore.document`. ```python import datasets from langchain_core.documents import Document # Charger le jeu de données guest_dataset = datasets.load_dataset("agents-course/unit3-invitees", split="train") # Convertir les entrées du jeu de données en objets Document docs = [ Document( page_content="\n".join([ f"Name: {guest['name']}", f"Relation: {guest['relation']}", f"Description: {guest['description']}", f"Email: {guest['email']}" ]), metadata={"name": guest["name"]} ) for guest in guest_dataset ] ``` Dans le code ci-dessus, nous : - Chargeons le jeu de données - Convertissons chaque entrée d'invité en un objet `Document` avec du contenu formaté - Stockons les objets `Document` dans une liste Cela signifie que nous avons toutes nos données bien disponibles pour pouvoir commencer à configurer notre récupération. ### Étape 2 : Créer l'outil de récupération Maintenant, créons un outil personnalisé qu'Alfred peut utiliser pour rechercher dans nos informations sur les invités. Nous utiliserons le `BM25Retriever` du module `langchain_community.retrievers` pour créer un outil de récupération. > [!TIP] > Le BM25Retriever est un excellent point de départ pour la récupération, mais pour une recherche sémantique plus avancée, vous pourriez considérer l'utilisation de récupérateurs basés sur des embeddings comme ceux de sentence-transformers. ```python from smolagents import Tool from langchain_community.retrievers import BM25Retriever class GuestInfoRetrieverTool(Tool): name = "guest_info_retriever" description = "Récupère des informations détaillées sur les invités du gala basées sur leur nom ou relation." inputs = { "query": { "type": "string", "description": "Le nom ou la relation de l'invité sur lequel vous voulez des informations." } } output_type = "string" def __init__(self, docs): self.is_initialized = False self.retriever = BM25Retriever.from_documents(docs) def forward(self, query: str): results = self.retriever.get_relevant_documents(query) if results: return "\n\n".join([doc.page_content for doc in results[:3]]) else: return "Aucune information d'invité correspondante trouvée." # Initialiser l'outil guest_info_tool = GuestInfoRetrieverTool(docs) ``` Comprenons cet outil étape par étape : - Le `name` et la `description` aident l'agent à comprendre quand et comment utiliser cet outil - Les `inputs` définissent quels paramètres l'outil attend (dans ce cas, une requête de recherche) - Nous utilisons un `BM25Retriever`, qui est un algorithme de récupération de texte puissant qui ne nécessite pas d'*embeddings* - La méthode `forward` traite la requête et retourne les informations d'invité les plus pertinentes Nous utiliserons le `BM25Retriever` du module `llama_index.retrievers.bm25` pour créer un outil de récupération. > [!TIP] > Le BM25Retriever est un excellent point de départ pour la récupération, mais pour une recherche sémantique plus avancée, vous pourriez considérer l'utilisation de récupérateurs basés sur des *embeddings* comme ceux de sentence-transformers. ```python from llama_index.core.tools import FunctionTool from llama_index.retrievers.bm25 import BM25Retriever bm25_retriever = BM25Retriever.from_defaults(nodes=docs) def get_guest_info_retriever(query: str) -> str: """Récupère des informations détaillées sur les invités du gala basées sur leur nom ou relation.""" results = bm25_retriever.retrieve(query) if results: return "\n\n".join([doc.text for doc in results[:3]]) else: return "Aucune information d'invité correspondante trouvée." # Initialiser l'outil guest_info_tool = FunctionTool.from_defaults(get_guest_info_retriever) ``` Comprenons cet outil étape par étape : - La *docstring* aide l'agent à comprendre quand et comment utiliser cet outil - Les décorateurs de type définissent quels paramètres l'outil attend (dans ce cas, une requête de recherche) - Nous utilisons un `BM25Retriever`, qui est un algorithme de récupération de texte puissant qui ne nécessite pas d'*embeddings* - La méthode traite la requête et retourne les informations d'invité les plus pertinentes Nous utiliserons le `BM25Retriever` du module `langchain_community.retrievers` pour créer un outil de récupération. > [!TIP] > Le BM25Retriever est un excellent point de départ pour la récupération, mais pour une recherche sémantique plus avancée, vous pourriez considérer l'utilisation de récupérateurs basés sur des *embeddings* comme ceux de sentence-transformers. ```python from langchain_community.retrievers import BM25Retriever from langchain_core.tools import Tool bm25_retriever = BM25Retriever.from_documents(docs) def extract_text(query: str) -> str: """Récupère des informations détaillées sur les invités du gala basées sur leur nom ou relation.""" results = bm25_retriever.invoke(query) if results: return "\n\n".join([doc.page_content for doc in results[:3]]) else: return "Aucune information d'invité correspondante trouvée." guest_info_tool = Tool( name="guest_info_retriever", func=extract_text, description="Récupère des informations détaillées sur les invités du gala basées sur leur nom ou relation." ) ``` Comprenons cet outil étape par étape : - Le `name` et la `description` aident l'agent à comprendre quand et comment utiliser cet outil - Les décorateurs de type définissent quels paramètres l'outil attend (dans ce cas, une requête de recherche) - Nous utilisons un `BM25Retriever`, qui est un algorithme de récupération de texte puissant qui ne nécessite pas d'*embeddings* - La méthode traite la requête et retourne les informations d'invité les plus pertinentes ### Étape 3 : Intégrer l'outil avec Alfred Enfin, assemblons le tout en créant notre agent et en l'équipant de notre outil personnalisé : ```python from smolagents import CodeAgent, InferenceClientModel # Initialiser le modèle Hugging Face model = InferenceClientModel() # Créer Alfred, notre agent de gala, avec l'outil d'informations sur les invités alfred = CodeAgent(tools=[guest_info_tool], model=model) # Exemple de requête qu'Alfred pourrait recevoir pendant le gala response = alfred.run("Parlez-moi de notre invitée nommée 'Lady Ada Lovelace'.") print("🎩 Réponse d'Alfred :") print(response) ``` Sortie attendue : ``` 🎩 Réponse d'Alfred : Basé sur les informations que j'ai récupérées, Lady Ada Lovelace est une mathématicienne estimée et une amie. Elle est renommée pour son travail pionnier en mathématiques et en informatique, souvent célébrée comme la première programmeuse informatique en raison de son travail sur la machine analytique de Charles Babbage. Son adresse email est ada.lovelace@example.com. ``` Ce qui se passe dans cette étape finale : - Nous initialisons un modèle Hugging Face en utilisant la classe `InferenceClientModel` - Nous créons notre agent (Alfred) comme un `CodeAgent`, qui peut exécuter du code Python pour résoudre des problèmes - Nous demandons à Alfred de récupérer des informations sur une invitée nommée "Lady Ada Lovelace" ```python from llama_index.core.agent.workflow import AgentWorkflow from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI # Initialiser le modèle Hugging Face llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") # Créer Alfred, notre agent de gala, avec l'outil d'informations sur les invités alfred = AgentWorkflow.from_tools_or_functions( [guest_info_tool], llm=llm, ) # Exemple de requête qu'Alfred pourrait recevoir pendant le gala response = await alfred.run("Parlez-moi de notre invitée nommée 'Lady Ada Lovelace'.") print("🎩 Réponse d'Alfred :") print(response) ``` Sortie attendue : ``` 🎩 Réponse d'Alfred : Lady Ada Lovelace est une mathématicienne estimée et amie, renommée pour son travail pionnier en mathématiques et en informatique. Elle est célébrée comme la première programmeuse informatique en raison de son travail sur la machine analytique de Charles Babbage. Son email est ada.lovelace@example.com. ``` Ce qui se passe dans cette étape finale : - Nous initialisons un modèle Hugging Face en utilisant la classe `HuggingFaceInferenceAPI` - Nous créons notre agent (Alfred) comme un `AgentWorkflow`, incluant l'outil que nous venons de créer - Nous demandons à Alfred de récupérer des informations sur une invitée nommée "Lady Ada Lovelace" ```python from typing import TypedDict, Annotated from langgraph.graph.message import add_messages from langchain_core.messages import AnyMessage, HumanMessage, AIMessage from langgraph.prebuilt import ToolNode from langgraph.graph import START, StateGraph from langgraph.prebuilt import tools_condition from langchain_huggingface import HuggingFaceEndpoint, ChatHuggingFace # Générer l'interface de chat, incluant les outils llm = HuggingFaceEndpoint( repo_id="Qwen/Qwen2.5-Coder-32B-Instruct", huggingfacehub_api_token=HUGGINGFACEHUB_API_TOKEN, ) chat = ChatHuggingFace(llm=llm, verbose=True) tools = [guest_info_tool] chat_with_tools = chat.bind_tools(tools) # Générer l'AgentState et le graphe d'agent class AgentState(TypedDict): messages: Annotated[list[AnyMessage], add_messages] def assistant(state: AgentState): return { "messages": [chat_with_tools.invoke(state["messages"])], } ## Le graphe builder = StateGraph(AgentState) # Définir les nœuds : ils font le travail builder.add_node("assistant", assistant) builder.add_node("tools", ToolNode(tools)) # Définir les arêtes : elles déterminent comment le flux de contrôle se déplace builder.add_edge(START, "assistant") builder.add_conditional_edges( "assistant", # Si le dernier message nécessite un outil, router vers les outils # Sinon, fournir une réponse directe tools_condition, ) builder.add_edge("tools", "assistant") alfred = builder.compile() messages = [HumanMessage(content="Parlez-moi de notre invitée nommée 'Lady Ada Lovelace'.")] response = alfred.invoke({"messages": messages}) print("🎩 Réponse d'Alfred :") print(response['messages'][-1].content) ``` Sortie attendue : ``` 🎩 Réponse d'Alfred : Lady Ada Lovelace est une mathématicienne estimée et pionnière en informatique, souvent célébrée comme la première programmeuse informatique en raison de son travail sur la machine analytique de Charles Babbage. ``` Ce qui se passe dans cette étape finale : - Nous initialisons un modèle Hugging Face en utilisant la classe `HuggingFaceEndpoint`. Nous générons aussi une interface de chat et ajoutons les outils. - Nous créons notre agent (Alfred) comme un `StateGraph`, qui combine 2 nœuds (`assistant`, `tools`) en utilisant une arête - Nous demandons à Alfred de récupérer des informations sur une invitée nommée "Lady Ada Lovelace" ## Exemple d'interaction Pendant le gala, une conversation pourrait se dérouler comme ceci : **Vous :** "Alfred, qui est ce monsieur qui parle à l'ambassadeur ?" **Alfred :** *recherche rapidement dans la base de données des invités* "C'est le Dr. Nikola Tesla, monsieur. C'est un vieil ami de votre période à l'université. Il vient récemment de breveter un nouveau système de transmission d'énergie sans fil et serait ravi d'en discuter avec vous. N'oubliez pas qu'il est passionné par les pigeons, donc cela pourrait faire une bonne conversation." ```json { "name": "Dr. Nikola Tesla", "relation": "vieil ami des jours d'université", "description": "Le Dr. Nikola Tesla est un vieil ami de votre période à l'université. Il vient récemment de breveter un nouveau système de transmission d'énergie sans fil et serait ravi d'en discuter avec vous. N'oubliez pas qu'il est passionné par les pigeons, donc cela pourrait faire une bonne conversation.", "email": "nikola.tesla@gmail.com" } ``` ## Aller plus loin Maintenant qu'Alfred peut récupérer des informations sur les invités, considérez comment vous pourriez améliorer ce système : 1. **Améliorer le récupérateur** pour utiliser un algorithme plus sophistiqué comme ceux disponibles dans [`sentence-transformers`](https://www.sbert.net/) 2. **Implémenter une mémoire de conversation** pour qu'Alfred se souvienne des interactions précédentes 3. **Combiner avec la recherche web** pour obtenir les dernières informations sur les invités inconnus 4. **Intégrer plusieurs index** pour obtenir des informations plus complètes à partir de sources vérifiées Maintenant Alfred est entièrement équipé pour gérer sans effort les questions sur les invités, s'assurant que votre gala soit mémorisé comme l'événement le plus sophistiqué et délicieux du siècle ! > [!TIP] > Essayez d'étendre l'outil de récupération pour aussi retourner des amorces de conversation basées sur les intérêts ou l'arrière-plan de chaque invité. Comment modifieriez-vous l'outil pour accomplir cela ? > > Quand vous avez terminé, implémentez votre outil de récupération d'invités dans le fichier retriever.py du Space. ================================================ FILE: units/fr/unit3/agentic-rag/tools.mdx ================================================ # Création et intégration d'outils pour votre agent Dans cette section, nous allons donner à Alfred l'accès au web, lui permettant de trouver les dernières nouvelles et mises à jour mondiales. De plus, il aura accès aux données météorologiques et aux statistiques de téléchargement des modèles du Hub d'Hugging Face Hub, pour qu'il puisse faire des conversations pertinentes sur des sujets frais. ## Donnez à votre agent l'accès au web Rappelez-vous que nous voulons qu'Alfred établisse sa présence comme un véritable hôte de la renaissance, avec une connaissance approfondie du monde. Pour ce faire, nous devons nous assurer qu'Alfred a accès aux dernières nouvelles et informations sur le monde. Commençons par créer un outil de recherche web pour Alfred ! ```python from smolagents import DuckDuckGoSearchTool # Initialiser l'outil de recherche DuckDuckGo search_tool = DuckDuckGoSearchTool() # Exemple d'usage results = search_tool("Qui est l'actuel Président de la France ?") print(results) ``` Sortie attendue : ``` L'actuel Président de la France est Emmanuel Macron. ``` ```python from llama_index.tools.duckduckgo import DuckDuckGoSearchToolSpec from llama_index.core.tools import FunctionTool # Initialiser l'outil de recherche DuckDuckGo tool_spec = DuckDuckGoSearchToolSpec() search_tool = FunctionTool.from_defaults(tool_spec.duckduckgo_full_search) # Exemple d'usage response = search_tool("Qui est l'actuel Président de la France ?") print(response.raw_output[-1]['body']) ``` Sortie attendue : ``` Le Président de la République française est le chef d'État de la France. L'actuel Président est Emmanuel Macron depuis le 14 mai 2017 après avoir battu Marine Le Pen au second tour de l'élection présidentielle le 7 mai 2017. Liste des présidents français (Cinquième République) N° Portrait Nom ... ``` ```python from langchain_community.tools import DuckDuckGoSearchRun search_tool = DuckDuckGoSearchRun() results = search_tool.invoke("Qui est l'actuel Président de la France ?") print(results) ``` Sortie attendue : ``` Emmanuel Macron (né le 21 décembre 1977 à Amiens, France) est un banquier et homme politique français qui a été élu président de la France en 2017... ``` ## Création d'un outil personnalisé pour les informations météorologiques afin de programmer le feu d'artifice Le gala parfait aurait un feu d'artifice dans un ciel clair, nous devons nous assurer qu'il ne soit pas annulé à cause du mauvais temps. Créons un outil personnalisé qui peut être utilisé pour appeler une API météo externe et obtenir les informations pour un lieu donné. > [!TIP] > Par souci de simplicité, nous utilisons une API météorologique factice pour cet exemple. Si vous voulez utiliser une véritable API, vous pourriez implémenter un outil utilisant l'API OpenWeatherMap comme dans l'Unité 1. ```python from smolagents import Tool import random class WeatherInfoTool(Tool): name = "weather_info" description = "Récupère des informations météorologiques factices pour un lieu donné." inputs = { "location": { "type": "string", "description": "Le lieu pour lequel obtenir les informations météorologiques." } } output_type = "string" def forward(self, location: str): # Données météorologiques factices weather_conditions = [ {"condition": "Pluvieux", "temp_c": 15}, {"condition": "Clair", "temp_c": 25}, {"condition": "Venteux", "temp_c": 20} ] # Sélectionner aléatoirement une condition météorologique data = random.choice(weather_conditions) return f"Météo à {location}: {data['condition']}, {data['temp_c']}°C" # Initialiser l'outil weather_info_tool = WeatherInfoTool() ``` ```python import random from llama_index.core.tools import FunctionTool def get_weather_info(location: str) -> str: """Récupère des informations météorologiques factices pour un lieu donné.""" # Données météorologiques factices weather_conditions = [ {"condition": "Pluvieux", "temp_c": 15}, {"condition": "Clair", "temp_c": 25}, {"condition": "Venteux", "temp_c": 20} ] # Sélectionner aléatoirement une condition météorologique data = random.choice(weather_conditions) return f"Météo à {location}: {data['condition']}, {data['temp_c']}°C" # Initialiser l'outil weather_info_tool = FunctionTool.from_defaults(get_weather_info) ``` ```python from langchain_core.tools import Tool import random def get_weather_info(location: str) -> str: """Récupère des informations météorologiques factices pour un lieu donné.""" # Données météorologiques factices weather_conditions = [ {"condition": "Pluvieux", "temp_c": 15}, {"condition": "Clair", "temp_c": 25}, {"condition": "Venteux", "temp_c": 20} ] # Sélectionner aléatoirement une condition météorologique data = random.choice(weather_conditions) return f"Météo à {location}: {data['condition']}, {data['temp_c']}°C" # Initialiser l'outil weather_info_tool = Tool( name="get_weather_info", func=get_weather_info, description="Récupère des informations météorologiques factices pour un lieu donné." ) ``` ## Création d'un outil pour obtenir les statistiques du Hub concernant les constructeurs d'IA influents Le gala réunit le gratin des constructeurs d'IA. Alfred veut les impressionner en discutant de leurs modèles, jeux de données et Spaces les plus populaires. Nous créerons un outil pour récupérer les statistiques des modèles du Hub à partir d'un nom d'utilisateur. ```python from smolagents import Tool from huggingface_hub import list_models class HubStatsTool(Tool): name = "hub_stats" description = "Récupère le modèle le plus téléchargé d'un auteur spécifique sur le Hugging Face Hub." inputs = { "author": { "type": "string", "description": "Le nom d'utilisateur de l'auteur/organisation du modèle pour trouver des modèles." } } output_type = "string" def forward(self, author: str): try: # Lister les modèles de l'auteur spécifié, triés par téléchargements models = list(list_models(author=author, sort="downloads", direction=-1, limit=1)) if models: model = models[0] return f"Le modèle le plus téléchargé par {author} est {model.id} avec {model.downloads:,} téléchargements." else: return f"Aucun modèle trouvé pour l'auteur {author}." except Exception as e: return f"Erreur lors de la récupération des modèles pour {author}: {str(e)}" # Initialiser l'outil hub_stats_tool = HubStatsTool() # Exemple d'usage print(hub_stats_tool("facebook")) # Exemple : Obtenir le modèle le plus téléchargé par Facebook ``` Sortie attendue : ``` Le modèle le plus téléchargé par facebook est facebook/esmfold_v1 avec 12,544,550 téléchargements. ``` ```python import random from llama_index.core.tools import FunctionTool from huggingface_hub import list_models def get_hub_stats(author: str) -> str: """Récupère le modèle le plus téléchargé d'un auteur spécifique sur le Hugging Face Hub.""" try: # Lister les modèles de l'auteur spécifié, triés par téléchargements models = list(list_models(author=author, sort="downloads", direction=-1, limit=1)) if models: model = models[0] return f"Le modèle le plus téléchargé par {author} est {model.id} avec {model.downloads:,} téléchargements." else: return f"Aucun modèle trouvé pour l'auteur {author}." except Exception as e: return f"Erreur lors de la récupération des modèles pour {author}: {str(e)}" # Initialiser l'outil hub_stats_tool = FunctionTool.from_defaults(get_hub_stats) # Exemple d'usage print(hub_stats_tool("facebook")) # Exemple : Obtenir le modèle le plus téléchargé par Facebook ``` Sortie attendue : ``` Le modèle le plus téléchargé par facebook est facebook/esmfold_v1 avec 12,544,550 téléchargements. ``` ```python from langchain_core.tools import Tool from huggingface_hub import list_models def get_hub_stats(author: str) -> str: """Récupère le modèle le plus téléchargé d'un auteur spécifique sur le Hugging Face Hub.""" try: # Lister les modèles de l'auteur spécifié, triés par téléchargements models = list(list_models(author=author, sort="downloads", direction=-1, limit=1)) if models: model = models[0] return f"Le modèle le plus téléchargé par {author} est {model.id} avec {model.downloads:,} téléchargements." else: return f"Aucun modèle trouvé pour l'auteur {author}." except Exception as e: return f"Erreur lors de la récupération des modèles pour {author}: {str(e)}" # Initialiser l'outil hub_stats_tool = Tool( name="get_hub_stats", func=get_hub_stats, description="Récupère le modèle le plus téléchargé d'un auteur spécifique sur le Hugging Face Hub." ) # Exemple d'usage print(hub_stats_tool.invoke("facebook")) # Exemple : Obtenir le modèle le plus téléchargé par Facebook ``` Sortie attendue : ``` Le modèle le plus téléchargé par facebook est facebook/esmfold_v1 avec 13 109 861 téléchargements. ``` Avec l'outil de statistiques, Alfred peut maintenant impressionner les constructeurs d'IA influents en discutant de leurs modèles les plus populaires. ## Intégration des outils Maintenant que nous avons tous les outils, intégrons-les dans l'agent d'Alfred : ```python from smolagents import CodeAgent, InferenceClientModel # Initialiser le modèle Hugging Face model = InferenceClientModel() # Créer Alfred avec tous les outils alfred = CodeAgent( tools=[search_tool, weather_info_tool, hub_stats_tool], model=model ) # Exemple de requête qu'Alfred pourrait recevoir pendant le gala response = alfred.run("Qu'est-ce que Facebook et quel est leur modèle le plus populaire ?") print("🎩 Réponse d'Alfred :") print(response) ``` Sortie attendue : ``` 🎩 Réponse d'Alfred : Facebook est un site web de réseau social où les utilisateurs peuvent se connecter, partager des informations et interagir avec d'autres. Le modèle le plus téléchargé par Facebook sur le Hugging Face Hub est ESMFold_v1. ``` ```python from llama_index.core.agent.workflow import AgentWorkflow from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI # Initialiser le modèle Hugging Face llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") # Créer Alfred avec tous les outils alfred = AgentWorkflow.from_tools_or_functions( [search_tool, weather_info_tool, hub_stats_tool], llm=llm ) # Exemple de requête qu'Alfred pourrait recevoir pendant le gala response = await alfred.run("Qu'est-ce que Facebook et quel est leur modèle le plus populaire ?") print("🎩 Réponse d'Alfred :") print(response) ``` Sortie attendue : ``` 🎩 Réponse d'Alfred : Facebook est un service de réseau social et une entreprise technologique basée à Menlo Park, en Californie. Elle a été fondée par Mark Zuckerberg et permet aux gens de créer des profils, se connecter avec des amis et la famille, partager des photos et vidéos, et rejoindre des groupes basés sur des intérêts partagés. Le modèle le plus populaire par Facebook sur le Hugging Face Hub est facebook/esmfold_v1 avec 13 109 861 téléchargements. ``` ```python from typing import TypedDict, Annotated from langgraph.graph.message import add_messages from langchain_core.messages import AnyMessage, HumanMessage, AIMessage from langgraph.prebuilt import ToolNode from langgraph.graph import START, StateGraph from langgraph.prebuilt import tools_condition from langchain_huggingface import HuggingFaceEndpoint, ChatHuggingFace # Générer l'interface de chat, incluant les outils llm = HuggingFaceEndpoint( repo_id="Qwen/Qwen2.5-Coder-32B-Instruct", huggingfacehub_api_token=HUGGINGFACEHUB_API_TOKEN, ) chat = ChatHuggingFace(llm=llm, verbose=True) tools = [search_tool, weather_info_tool, hub_stats_tool] chat_with_tools = chat.bind_tools(tools) # Générer l'AgentState et le graphe d'agent class AgentState(TypedDict): messages: Annotated[list[AnyMessage], add_messages] def assistant(state: AgentState): return { "messages": [chat_with_tools.invoke(state["messages"])], } ## Le graphe builder = StateGraph(AgentState) # Définir les nœuds : ils font le travail builder.add_node("assistant", assistant) builder.add_node("tools", ToolNode(tools)) # Définir les arêtes : elles déterminent comment le flux de contrôle se déplace builder.add_edge(START, "assistant") builder.add_conditional_edges( "assistant", # Si le dernier message nécessite un outil, router vers les outils # Sinon, fournir une réponse directe tools_condition, ) builder.add_edge("tools", "assistant") alfred = builder.compile() messages = [HumanMessage(content="Qui est Facebook et quel est leur modèle le plus populaire ?")] response = alfred.invoke({"messages": messages}) print("🎩 Réponse d'Alfred :") print(response['messages'][-1].content) ``` Sortie attendue : ``` 🎩 Réponse d'Alfred : Facebook est une entreprise de médias sociaux connue pour son site de réseau social, Facebook, ainsi que d'autres services comme Instagram et WhatsApp. Le modèle le plus téléchargé par Facebook sur le Hugging Face Hub est facebook/esmfold_v1 avec 13 202 321 téléchargements. ``` ## Conclusion En intégrant ces outils, Alfred est maintenant équipé pour gérer une variété de tâches, des recherches web aux mises à jour météorologiques et aux statistiques de modèles. Cela garantit qu'il reste l'hôte le plus informé et engageant du gala. > [!TIP] > Essayez d'implémenter un outil qui peut être utilisé pour obtenir les dernières nouvelles sur un sujet spécifique. > > Quand vous avez terminé, implémentez vos outils personnalisés dans le fichier tools.py. ================================================ FILE: units/fr/unit4/additional-readings.mdx ================================================ # Et maintenant ? Quels sujets devrais-je apprendre ? L'IA agentique est un domaine en évolution rapide, et comprendre les protocoles fondamentaux est essentiel pour construire des systèmes intelligents et autonomes. Deux standards importants avec lesquels vous devriez vous familiariser sont : - Le ***Model Context Protocol* (MCP)** - Le ***Agent-to-Agent Protocol* (A2A)** ## 🔌 *Model Context Protocol* (MCP) Le ***Model Context Protocol* (MCP)** d'Anthropic est un standard ouvert qui permet aux modèles de se connecter de manière sécurisée et transparente **avec des outils externes, des sources de données et des applications**, rendant les agents plus compétents et autonomes. Pensez à MCP comme un **adaptateur universel**, comme un port USB-C, qui permet aux modèles de se connecter à divers environnements numériques **sans avoir besoin d'intégration personnalisée pour chacun**. MCP gagne rapidement en popularité dans l'industrie, avec des entreprises majeures comme *OpenAI* et *Google* qui commencent à l'adopter. 📚 En savoir plus : - [Annonce officielle et documentation d'Anthropic](https://www.anthropic.com/news/model-context-protocol) - [MCP sur Wikipedia](https://en.wikipedia.org/wiki/Model_Context_Protocol) - [Un article de blog sur MCP](https://huggingface.co/blog/Kseniase/mcp) - [Le cours d'Hugging Face sur le sujet](https://huggingface.co/learn/mcp-course/unit0/introduction) ## 🤝 Protocole *Agent-to-Agent* (A2A) Google a développé le **protocole *Agent-to-Agent* (A2A)** comme un complément au *Model Context Protocol* (MCP) d'Anthropic. Alors que MCP connecte les agents aux outils externes, **A2A connecte les agents entre eux**, ouvrant la voie à des systèmes multi-agents coopératifs qui peuvent travailler ensemble pour résoudre des problèmes complexes. 📚 En savoir plus : - [L'annonce de Google](https://developers.googleblog.com/en/a2a-a-new-era-of-agent-interoperability/) ================================================ FILE: units/fr/unit4/conclusion.mdx ================================================ # Conclusion **Félicitations pour avoir terminé le Cours sur les Agents !** Grâce à votre persévérance et à votre dévouement, vous avez acquis une base solide dans le monde des agents IA. Mais terminer ce cours n'est **pas la fin de votre parcours**. C'est juste le début : n'hésitez pas à explorer la section suivante où nous partageons des ressources sélectionnées pour vous aider à continuer d'apprendre, y compris des sujets avancés comme les ***Protocol de Contexte Modèle (MCP)*** et au-delà. **Merci** d'avoir participé à ce cours. **Nous espérons que vous l'avez apprécié autant que nous avons aimé l'écrire**. Et n'oubliez pas : **continuez à apprendre, restez géniaux 🤗** ================================================ FILE: units/fr/unit4/get-your-certificate.mdx ================================================ # Obtenez votre certificat 🎓 Si vous avez obtenu un score **supérieur à 30%, félicitations ! 👏 Vous êtes maintenant éligible pour réclamer votre certificat officiel.** Suivez les étapes ci-dessous pour le recevoir : 1. Visitez la [page du certificat](https://huggingface.co/spaces/agents-course/Unit4-Final-Certificate). 2. **Connectez-vous** avec votre compte Hugging Face en utilisant le bouton fourni. 3. **Entrez votre nom complet**. C'est le nom qui apparaîtra sur votre certificat. 4. Cliquez sur **"*Obtenir mon certificat*"** pour vérifier votre score et télécharger votre certificat. Congrats! Une fois que vous avez obtenu votre certificat, n'hésitez pas à : - L'ajouter à votre **profil *LinkedIn*** 🧑‍💼 - Le partager sur **X**, **Bluesky**, etc. 🎉 **N'oubliez pas de taguer [@huggingface](https://huggingface.co/huggingface). Nous serions super fiers et nous aimerions vous encourager ! 🤗** > [!TIP] > Si vous avez des problèmes avec la soumission, veuillez ouvrir une discussion sur [l'onglet communauté de la certification](https://huggingface.co/spaces/agents-course/Unit4-Final-Certificate/discussions). ================================================ FILE: units/fr/unit4/hands-on.mdx ================================================ # Le projet pratique final Maintenant que vous êtes prêt à plonger plus profondément dans la création de votre agent, voyons comment vous pouvez le soumettre pour l'évaluer. ## Le jeu de données Le jeu de données utilisé pour le classement se compose de 20 questions extraites des questions de niveau 1 de la partie **validation** de GAIA. Les questions choisies ont été filtrées en fonction du nombre d'outils et d'étapes nécessaires pour répondre à une question. Sur la base de l'état actuel du *benchmark* GAIA, nous pensons que vous faire viser 30% sur les questions de niveau 1 est un test équitable. GAIA current status! ## Le processus Maintenant, la grande question dans votre esprit est probablement : « Comment puis-je commencer à soumettre ? » Pour cette unité, nous avons créé une API qui vous permettra d'obtenir les questions et d'envoyer vos réponses pour évaluation. Voici un résumé des routes (voir la [documentation en direct](https://agents-course-unit4-scoring.hf.space/docs) pour les détails interactifs) : * **`GET /questions`** : Récupérer la liste complète des questions d'évaluation filtrées. * **`GET /random-question`** : Récupérer une seule question aléatoire de la liste. * **`GET /files/{task_id}`** : Télécharger un fichier spécifique associé à un ID de tâche donné. * **`POST /submit`** : Soumettre les réponses de l'agent, calculer le score et mettre à jour le classement. La fonction de soumission comparera votre réponse à la vérité terrain via une **CORRESPONDANCE EXACTE**, donc formulez bien vos *prompts* ! L'équipe GAIA a partagé un exemple de formulation pour votre agent [ici](https://huggingface.co/spaces/gaia-benchmark/leaderboard) (pour les besoins de ce cours, assurez-vous de ne pas inclure le texte "FINAL ANSWER" dans votre soumission, faites simplement que votre agent réponde avec la réponse et rien d'autre). 🎨 **Personnalisez le gabarit !** Pour démontrer le processus d'interaction avec l'API, nous avons inclus un [gabarit de base](https://huggingface.co/spaces/agents-course/Final_Assignment_Template) comme point de départ. N'hésitez pas à le changer, et **nous vous encourageons activement à le faire**, y ajouter ou le restructurer complètement ! Modifiez-le de la manière qui convient le mieux à votre approche et à votre créativité. Pour soumettre ces gabarits, calculez 3 éléments nécessaires à l'API : * **Nom d'utilisateur :** Votre nom d'utilisateur Hugging Face (ici obtenu via la connexion Gradio), qui est utilisé pour identifier votre soumission. * **Lien de code (`agent_code`) :** l'URL pointant vers le code de votre *Space* Hugging Face (`.../tree/main`) à des fins de vérification, alors veuillez garder votre *Space* public. * **Réponses (`answers`) :** La liste des réponses (`{"task_id": ..., "submitted_answer": ...}`) générées par votre agent pour la notation. Nous vous encourageons donc à commencer par dupliquer ce [gabarit](https://huggingface.co/spaces/agents-course/Final_Assignment_Template) sur votre propre profil Hugging Face. 🏆 Consultez le classement [ici](https://huggingface.co/spaces/agents-course/Students_leaderboard) *Une note amicale : Ce classement est destiné à s'amuser ! Nous savons qu'il est possible de soumettre des scores sans vérification complète. Si nous constatons qu'un trop grand nombre de scores élevés sont affichés sans lien public pour les étayer, il se peut que nous devions revoir, ajuster ou supprimer certaines entrées afin de préserver l'utilité du classement.* Le classement montrera le lien vers votre *Space* et le code qu'il contient. Puisque ce classement est réservé aux étudiants, veuillez le garder public si vous obtenez un score dont vous êtes fier. ================================================ FILE: units/fr/unit4/introduction.mdx ================================================ # Introduction à l'unité finale [[introduction]] AI Agents Course thumbnail Bienvenue dans l'unité finale du cours ! 🎉 Jusqu'à présent, vous avez **acquis de solides connaissances sur les agents**, depuis la compréhension de leurs composants jusqu'à la création de vos propres agents. Avec ces connaissances, vous êtes maintenant prêt à en **construire des puissants** et à rester à jour avec les dernières avancées dans ce domaine en rapide évolution. Cette unité consiste entièrement à appliquer ce que vous avez appris. C'est votre **projet pratique final** et le compléter est votre ticket pour obtenir le **certificat du cours**. ## Quel est le défi ? Vous allez créer votre propre agent et **évaluer ses performances en utilisant un sous-ensemble du [*benchmark* GAIA](https://huggingface.co/spaces/gaia-benchmark/leaderboard)**. Pour réussir le cours, votre agent doit obtenir un score de **30% ou plus** sur le *benchmark*. Atteignez cet objectif, et vous obtiendrez votre **Certificat de Réussite**, reconnaissant officiellement votre expertise. 🏅 De plus, voyez comment vous vous classez face à vos pairs ! Un **[Classement des Étudiants](https://huggingface.co/spaces/agents-course/Students_leaderboard)** dédié est disponible pour que vous puissiez soumettre vos scores et voir les progrès de la communauté. > ** 🚨 Attention : Unité Avancée et Pratique** > > Veuillez noter que cette unité adopte une approche plus pratique. La réussite dans cette section nécessitera **des connaissances en programmation plus avancées** et reposera sur le fait que vous naviguerez dans des tâches avec **moins de conseils explicites** que dans les parties précédentes du cours. Cela vous semble excitant ? Commençons ! 🚀 ================================================ FILE: units/fr/unit4/what-is-gaia.mdx ================================================ # Qu'est-ce que GAIA ? [GAIA](https://huggingface.co/papers/2311.12983) est un ***benchmark* conçu pour évaluer les assistants IA sur des tâches du monde réel** nécessitant une combinaison de capacités fondamentales comme le raisonnement, la compréhension multimodale, la navigation *web* et l'utilisation d'outils. Il a été introduit dans l'article _"[GAIA: A Benchmark for General AI Assistants](https://huggingface.co/papers/2311.12983)"_. Le *benchmark* comprend **466 questions soigneusement sélectionnées** qui sont **conceptuellement simples pour les humains**, mais **remarquablement difficiles pour les systèmes d'IA actuels**. Pour illustrer l'écart : - **Humains** : ~92% de taux de réussite - **GPT-4 avec *plugins*** : ~15% - ***Deep Research* (OpenAI)** : 67,36% sur le jeu de validation GAIA souligne les limitations actuelles des modèles et fournit un *benchmark* rigoureux pour évaluer les progrès vers des assistants vraiment polyvalents. ## 🌱 Principes Fondamentaux de GAIA GAIA est soigneusement conçu autour des piliers suivants : - 🔍 **Difficulté du monde réel** : Les tâches nécessitent un raisonnement en plusieurs étapes, une compréhension multimodale et une interaction avec des outils. - 🧾 **Interprétabilité humaine** : Malgré leur difficulté pour l'IA, les tâches restent conceptuellement simples et faciles à suivre pour les humains. - 🛡️ **Absence de jeu** : Les réponses correctes exigent l'exécution complète de la tâche, rendant la force brute inefficace. - 🧰 **Simplicité d'évaluation** : Les réponses sont concises, factuelles et non ambiguës, idéales pour l'évaluation comparative. ## Niveaux de Difficulté Les tâches de GAIA sont organisées en **trois niveaux de complexité croissante**, chacun testant des compétences spécifiques : - **Niveau 1** : Nécessite moins de 5 étapes et une utilisation minimale d'outils. - **Niveau 2** : Implique un raisonnement plus complexe et une coordination entre plusieurs outils et 5-10 étapes. - **Niveau 3** : Exige une planification à long terme et une intégration avancée de divers outils. ![GAIA levels](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit4/gaia_levels.png) ## Exemple d'une question difficile > *Which of the fruits shown in the 2008 painting "Embroidery from Uzbekistan" were served as part of the October 1949 breakfast menu for the ocean liner that was later used as a floating prop for the film "The Last Voyage"? Give the items as a comma-separated list, ordering them in clockwise order based on their arrangement in the painting starting from the 12 o'clock position. Use the plural form of each fruit.* > Parmi les fruits représentés dans le tableau de 2008 intitulé « Broderie d'Ouzbékistan », quels sont ceux qui figuraient au menu du petit-déjeuner servi en octobre 1949 à bord du paquebot qui a ensuite servi d'accessoire flottant pour le film « Le dernier voyage » ? Donnez les éléments sous forme de liste séparée par des virgules, en les classant dans le sens des aiguilles d'une montre, en fonction de leur disposition dans le tableau, en commençant par la position 12 heures. Utilisez la forme plurielle de chaque fruit. Comme vous pouvez le voir, cette question défie les systèmes d'IA de plusieurs manières : - Nécessite un **format de réponse structuré** - Implique un **raisonnement multimodal** (par exemple, analyser des images) - Exige une **récupération multi-saut** de faits interdépendants : - Identifier les fruits dans la peinture - Découvrir quel paquebot a été utilisé dans *The Last Voyage* - Rechercher le menu du petit-déjeuner d'octobre 1949 pour ce navire - Nécessite un **séquençage correct** et une planification de haut niveau pour résoudre dans le bon ordre Ce type de tâche souligne où les LLM autonomes échouent souvent, faisant de GAIA un *benchmark* idéal pour **les systèmes basés sur des agents** qui peuvent raisonner, récupérer et exécuter sur plusieurs étapes et modalités. ![GAIA capabilities plot](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit4/gaia_capabilities.png) ## Évaluation en direct Pour encourager l'évaluation comparative continue, **GAIA fournit un classement public hébergé sur Hugging Face** où vous pouvez tester vos modèles contre **300 questions de test**. 👉 Consultez le classement [ici](https://huggingface.co/spaces/gaia-benchmark/leaderboard) Vous voulez plus loin sur le sujet de GAIA ? - 📄 [Lire l'article complet](https://huggingface.co/papers/2311.12983) - 📄 [Article de présentation de *Deep Research* par OpenAI](https://openai.com/index/introducing-deep-research/) - 📄 [*DeepResearch open-source* – Libérer nos agents de recherche](https://huggingface.co/blog/open-deep-research) ================================================ FILE: units/ko/_toctree.yml ================================================ - title: Unit 0. Welcome to the course sections: - local: unit0/introduction title: AI 에이전트 코스에 오신걸 환영합니다 🤗 - local: unit0/onboarding title: 온보딩(Onboarding), 첫 걸음 내딛기 ⛵ - local: unit0/discord101 title: (선택) Discord 101 - title: Unit 1. Introduction to Agents sections: - local: unit1/introduction title: 에이전트 소개 - local: unit1/what-are-agents title: 에이전트란? - local: unit1/quiz1 title: Quick Quiz 1 - local: unit1/what-are-llms title: 대규모 언어 모델(LLM)이란? - local: unit1/messages-and-special-tokens title: 메세지와 특수 토큰 - local: unit1/tools title: 도구란? - local: unit1/quiz2 title: Quick Quiz 2 - local: unit1/agent-steps-and-structure title: 사고-행동-관찰 주기를 통해 AI 에이전트 이해하기 - local: unit1/thoughts title: 사고, AI 에이전트의 내부 추론과 Re-Act 방식 - local: unit1/actions title: 액션, 에이전트가 환경과 상호작용할 수 있게 하기 - local: unit1/observations title: 관찰, 피드백을 통합하여 성찰하고 적응하기 - local: unit1/dummy-agent-library title: 더미 에이전트 라이브러리 - local: unit1/tutorial title: smolagents로 첫 번째 에이전트 만들기 - local: unit1/final-quiz title: Unit 1 Final Quiz - local: unit1/conclusion title: Conclusion - title: Unit 2. Frameworks for AI Agents sections: - local: unit2/introduction title: AI Agent 프레임워크 소개 - title: Unit 2.1 The smolagents framework sections: - local: unit2/smolagents/introduction title: smolagents 소개 - local: unit2/smolagents/why_use_smolagents title: smolagents를 왜 사용할까? - local: unit2/smolagents/quiz1 title: Quick Quiz 1 - local: unit2/smolagents/code_agents title: 코드를 사용하는 에이전트 만들기 - local: unit2/smolagents/tool_calling_agents title: 액션을 코드 조각(코드 스니펫)이나 JSON 블롭으로 작성하기 - local: unit2/smolagents/tools title: 도구 소개 - local: unit2/smolagents/retrieval_agents title: 검색 에이전트 - local: unit2/smolagents/quiz2 title: Quick Quiz 2 - local: unit2/smolagents/multi_agent_systems title: 멀티 에이전트 시스템 - local: unit2/smolagents/vision_agents title: 비전과 브라우저 에이전트 - local: unit2/smolagents/final_quiz title: 최종 Quiz - local: unit2/smolagents/conclusion title: 결론 - title: Unit 2.2 The LlamaIndex framework sections: - local: unit2/llama-index/introduction title: LLamaIndex 소개 - local: unit2/llama-index/llama-hub title: LlamaHub 소개 - local: unit2/llama-index/components title: LlamaIndex의 구성 요소 - local: unit2/llama-index/tools title: LlamaIndex에서 도구 사용하기 - local: unit2/llama-index/quiz1 title: Quick Quiz 1 - local: unit2/llama-index/agents title: LlamaIndex에서 에이전트 사용하기 - local: unit2/llama-index/workflows title: LlamaIndex에서 에이전트 워크플로우 만들기 - local: unit2/llama-index/quiz2 title: Quick Quiz 2 - local: unit2/llama-index/conclusion title: 결론 - title: Unit 2.3 The LangGraph framework sections: - local: unit2/langgraph/introduction title: LangGraph 소개 - local: unit2/langgraph/when_to_use_langgraph title: LangGraph란? - local: unit2/langgraph/building_blocks title: LangGraph의 구성 요소 - local: unit2/langgraph/first_graph title: 첫 번째 LangGraph 만들기 - local: unit2/langgraph/document_analysis_agent title: Document Analysis Graph - local: unit2/langgraph/quiz1 title: Quick Quiz 1 - local: unit2/langgraph/conclusion title: 결론 - title: Unit 4. Final Project - Create, Test, and Certify Your Agent sections: - local: unit4/introduction title: Introduction to the Final Unit - title: Bonus Unit 1. Fine-tuning an LLM for Function-calling sections: - local: bonus-unit1/introduction title: Introduction - local: bonus-unit1/what-is-function-calling title: What is Function Calling? ================================================ FILE: units/ko/bonus-unit1/introduction.mdx ================================================ # 소개[[introduction]] ![Bonus Unit 1 Thumbnail](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit1/thumbnail.jpg) 첫 번째 **Bonus Unit**에 오신 것을 환영합니다. 여기에서 **함수 호출을 위한 대형 언어 모델(LLM)을 미세 조정하는 방법**을 배우게 됩니다. 대형 언어 모델(LLM)에서 함수 호출은 *필수 학습* 기술이 되어 가고 있습니다. 여기서 핵심은 Unit 1에서 했던 것처럼 프롬프트 기반 접근 방식에만 의존하는 대신, 함수 호출을 통해 **학습 과정에서 직접 행동을 수행하고 관찰된 정보를 해석하도록** 모델을 훈련시켜 AI의 견고성을 높인다는 점입니다. > **Bonus Unit을 언제 진행해야 하나요?** > > 이 섹션은 **선택 사항**이며 Unit 1보다 **심화된 내용**을 다루므로, 지금 바로 진행하거나 이 과정을 통해 지식이 더 쌓인 후에 다시 살펴보셔도 좋습니다. > > 하지만 걱정하지 마세요. 이 Bonus Unit은 필요한 모든 정보를 담고 있어, 미세 조정의 내부 작동 방식을 아직 배우지 않으셨더라도 함수 호출을 위한 핵심 개념을 하나하나 안내해 드립니다. Bonus Unit을 가장 효과적으로 따라가려면: 1. 아직 Transformers로 대형 언어 모델(LLM)을 미세 조정하는 방법을 모른다면 [여기](https://huggingface.co/learn/nlp-course/chapter3/1?fw=pt)를 확인하세요. 2. `SFTTrainer`를 사용하여 모델을 미세 조정하는 방법을 알고 싶다면 [공식 문서](https://huggingface.co/learn/nlp-course/en/chapter11/1)를 참조하세요. --- ## 학습 내용[[what-you’ll-learn]] 1. **함수 호출** 최신 LLM이 대화를 구조화하여 **도구**를 호출할 수 있게 하는 방법을 배웁니다. 2. **LoRA (저차원 적응)** 계산 및 저장 오버헤드를 줄여주는 **경량화되고 효율적인** 미세 조정 방법입니다. LoRA는 대형 모델을 *더 빠르고 저렴하게 훈련하고, 쉽게 배포할 수 있게 합니다.* 3. 함수 호출 모델에서의 **사고 → 행동 → 관찰 사이클** 간단하지만 강력한 접근 방식으로, 모델이 언제(그리고 어떻게) 함수를 호출할지 결정하고, 중간 단계를 추적하며, 외부 도구나 API로부터 받은 결과를 해석하는 과정을 구조화합니다. 4. **새로운 특수 토큰** 모델이 다음 항목들을 구별할 수 있도록 특수한 마커를 도입합니다. - 내부 “사고 과정” 추론 - 함수 호출 요청 - 외부 도구로부터 돌아오는 응답 --- Bonus Unit을 마치면 다음을 할 수 있습니다. - **도구** 관련 API의 내부 작동 방식을 **이해**합니다. - LoRA 기법을 사용하여 모델을 **미세 조정**합니다. - 사고 → 행동 → 관찰 사이클을 **구현**하고 **수정**하여 견고하고 유지보수 가능한 함수 호출 워크플로를 만듭니다. - 모델의 내부 추론과 외부 행동을 원활하게 구분할 수 있도록 **특수 토큰을 설계 및 활용**합니다. 그리고 **함수를 호출하기 위해 직접 모델을 미세 조정**하게 됩니다. 🔥 이제 **함수 호출**에 대해 본격적으로 살펴보겠습니다! ================================================ FILE: units/ko/bonus-unit1/what-is-function-calling.mdx ================================================ # 함수 호출이란 무엇인가[[what-is-function-calling]] 함수 호출은 **LLM이 환경과 상호작용하여 동작을 수행하는 방법**입니다. 처음에는 [GPT-4에서 도입되었으며](https://openai.com/index/function-calling-and-other-api-updates/), 이후 다른 모델에서도 구현되었습니다. 에이전트의 도구처럼, 함수 호출은 모델에게 **주어진 환경에서 동작을 수행할 수 있는 능력**을 제공합니다. 다만 함수 호출 능력은 **모델 스스로 학습을 통해 체득한 것**이므로, 다른 에이전트 기법들보다 **프롬프트에 덜 의존**한다는 점입니다. Unit 1에서는 에이전트가 **도구를 사용하는 법을 학습한 것이 아니며**, 우리는 그저 도구 목록을 모델에게 제공했고, 모델이 **이 도구들을 활용해 계획을 생성할 것이라는 일반화 능력**에 의존했습니다. 여기서는 **함수 호출을 통해 에이전트가 도구를 사용할 수 있도록 미세 조정(학습)**합니다. ## 모델은 동작 수행을 어떻게 "학습"할까요?[[how-does-the-model-learn-to-take-an-action]] Unit 1에서는 에이전트의 일반적인 워크플로우를 살펴보았습니다. 사용자가 에이전트에 도구를 제공하고 질의를 전달하면, 모델은 다음 과정을 반복합니다. 1. *사고(Think)* : 목표를 달성하기 위해 어떤 동작을 수행해야 할지 고민합니다. 2. *행동(Act)* : 정해진 형식에 맞춰 행동을 수행하고, 일단 자신의 텍스트 응답 생성은 멈춥니다. 3. *관찰(Observe)* : 행동의 실행 결과를 외부로부터 받아옵니다. API를 통한 “일반적인” 대화는 아래처럼 사용자("user")와 어시스턴트("assistant")가 메시지를 주고받는 형태로 구성됩니다. ```python conversation = [ {"role": "user", "content": "I need help with my order"}, {"role": "assistant", "content": "I'd be happy to help. Could you provide your order number?"}, {"role": "user", "content": "It's ORDER-123"}, ] ``` 함수 호출은 이 대화의 흐름에 **새로운 역할("role")**을 추가합니다! 1. **행동(Action)**을 위한 새로운 역할 2. **관찰(Observation)**을 위한 새로운 역할 [Mistral API](https://docs.mistral.ai/capabilities/function_calling/)를 예로 들면, 대화 구조가 이렇게 바뀌게 됩니다. ```python conversation = [ { "role": "user", "content": "What's the status of my transaction T1001?" }, { "role": "assistant", "content": "", "function_call": { "name": "retrieve_payment_status", "arguments": "{\"transaction_id\": \"T1001\"}" } }, { "role": "tool", "name": "retrieve_payment_status", "content": "{\"status\": \"Paid\"}" }, { "role": "assistant", "content": "Your transaction T1001 has been successfully paid." } ] ``` > ...하지만 방금 함수 호출에 '새로운 역할'이 추가된다고 하지 않았나요? **그렇기도 하고 아니기도 합니다.** 이 경우를 비롯해 많은 API에서, 모델은 수행할 동작을 "assistant" 메시지로 출력합니다. 그러면 이후 채팅 템플릿이 이 메시지를 함수 호출을 위한 **특수 토큰**으로 변환하여 처리합니다. - `[AVAILABLE_TOOLS]` – 사용 가능한 도구 목록 시작 - `[/AVAILABLE_TOOLS]` – 사용 가능한 도구 목록 종료 - `[TOOL_CALLS]` – 도구를 호출(즉, **Action** 수행) - `[TOOL_RESULTS]` – 동작 결과(“Observe”) - `[/TOOL_RESULTS]` – 관찰 종료(이제 모델이 이어서 응답을 생성할 수 있음) 강의에서 함수 호출을 다시 다룰 예정이지만, 더 깊이 살펴보고 싶다면 [Mistral의 공식 문서](https://docs.mistral.ai/capabilities/function_calling/)를 참고하세요. --- 이제 함수 호출이 무엇이고 어떻게 작동하는지 배웠으니, 아직 해당 기능이 없는 모델인 [google/gemma-2-2b-it]([google/gemma-2-2b-it](https://huggingface.co/google/gemma-2-2b-it)에 새로운 특수 토큰을 덧붙이는 방식으로 함수 호출 기능을 직접 추가해보겠습니다. 이를 위해서는 **먼저 미세 조정과 LoRA**를 이해해야 합니다. ================================================ FILE: units/ko/unit0/discord101.mdx ================================================ # (선택 섹션) Discord 101 [[discord-101]] The Discord Etiquette 이 가이드는 게임 및 머신러닝(Machine Learning) 커뮤니티에서 인기 있는 무료 채팅 플랫폼, 디스코드(Discord)를 처음 사용하는 분들을 위한 안내서입니다. Hugging Face 커뮤니티 Discord 서버에서는 **10만 명 이상**의 멤버가 활동하고 있습니다. 아래 링크를 클릭하여 참여해 보세요!다른 사용자들과 만날 수 있는 좋은 장소입니다! ## Hugging Face 디스코드 채널에서 Agent 코스를 만나보세요! Starting on Discord can be a bit overwhelming, so here's a quick guide to help you navigate. 디스코드를 처음 이용하신다면 다소 낯설 수 있어, 퀵가이드를 준비했습니다. Hugging Face 커뮤니티 서버에서는 논문 토론, 이벤트 등 다양한 분야에 활발한 커뮤니티입니다. 먼저 [회원가입](http://hf.co/join/discord) 하신 후, `#introduce-yourself` 채널에서 간단한 자기소개를 남겨주세요! 이 서버에는 에이전트 코스 전용 4가지 채널이 있습니다! : - `agents-course-announcements`: **최신 코스 소식**을 확인하는 공간 - `🎓-agents-course-general`: **자유로운 대화와 토론** 을 위한 공간 - `agents-course-questions`: **질문 & 동료들과 도움 주고 받기** 위한 공간 - `agents-course-showcase`: **자신이 만든 최고의 AI 에이전트를 공유** 하기 위한 공간 추가로 : - `smolagents`: **라이브러리에 대한 논의 및 지원** 을 받을 수 있습니다. ## 디스코드 활용 팁 ### 서버에 참여하는 방법 Discord가 익숙하지 않다면, 서버 참여 방법에 대한 공식 가이드를 참고하세요! 간단한 절차는 다음과 같습니다 : 1. 초대 링크를 클릭합니다. 2. 디스코드 계정으로 로그인 하거나, 새 계정을 만듭니다. 3. 본인이 AI 에이전트가 아님을 인증하세요! 4. 별명과 아바타를 설정합니다. 5. "서버 참여(Join Server)"를 클릭합니다! ### 디스코드 효과적으로 활용하기 디스코드를 효과적으로 활용할 수 있는 몇 가지 팁! - **음성 채널** 도 제공되지만, 일반적으로는 텍스트 채팅이 더 많이 사용됩니다. - **마크다운 형식**을 사용할 수 있어, 코드 작성시 유용합니다. 링크에는 마크다운 사용이 제한될 수 있습니다! - **긴 대화**시 스레드를 활용하시면 더 편리합니다. 이 가이드가 도움이 되셨기를 바랍니다! 질문이 있으면 디스코드에서 언제든 문의해주세요. 🤗 ================================================ FILE: units/ko/unit0/introduction.mdx ================================================ # AI 에이전트 코스에 오신걸 환영합니다 🤗 [[introduction]]
AI Agents Course thumbnail
이미지 배경은 Scenario.com 을 활용하여 제작되었습니다.
오늘날 AI에서 가장 흥미로운 주제인 **에이전트(Agents)**에 오신 것을 환영합니다! 이 무료 코스에서는 **초급부터 전문가 수준**까지, AI 에이전트를 이해하고 활용하며 직접 구축하는 방법을 배울 수 있습니다. 첫 번째 유닛에서는 다음과 같은 내용을 다룹니다: - **강의 커리큘럼** 살펴보기 - **수강 방식 선택** (자기주도 학습 또는 인증 과정) - **인증 과정 및 마감일 정보** - 코스 운영팀 소개 - **Hugging Face** 계정 만들기. - **Discord 서버** 가입하고 다른 학습자 및 강사들과 소통하기 지금 바로 시작해 보세요! ## 이 코스에서 무엇을 배울 수 있나요? [[expect]] 해당 코스에서는 다음과 같은 내용을 학습합니다: - 📖 AI 에이전트의 **이론, 설계, 실전 활용**에 대해 공부합니다. - 🧑‍💻 [smolagents](https://huggingface.co/docs/smolagents/en/index), [LangChain](https://www.langchain.com/), and [LlamaIndex](https://www.llamaindex.ai/) 등의 **AI 에이전트 라이브러리** 활용법을 배웁니다. - 💾 Hugging Face Hub에 **자신이 만든 에이전트**를 공유하고, 커뮤니티에서 제작한 에이전트를 탐색합니다. - 🏆 **다른 학습자의 에이전트와 비교 평가**하는 챌린지에 참여합니다. - 🎓 과제를 완료하면 **수료 인증서**를 받을 수 있습니다. 그 외에도 다양한 내용을 다룹니다! 이 코스를 마치면 **AI 에이전트의 동작 원리를 이해하고, 최신 라이브러리와 도구를 활용하여 직접 구현하는 방법**을 익히게 됩니다. 👉 지금 바로 코스에 등록하세요! (HuggingFace는 개인정보 보호를 존중합니다. 이메일 주소는 **각 단원 공개시 링크, 챌린지 및 업데이트 정보**를 제공하는 용도로만 사용됩니다.) ## 이 코스는 어떻게 진행되나요? [[course-look-like]] 이 코스는 다음과 같이 구성됩니다: - *기본 개념 학습*: 에이전트 개념을 **이론적**으로 배우는 단계입니다. - *실습*: **기존 AI 에이전트 라이브러리**를 활용해 특정 환경에서 에이전트를 훈련하는 방법을 배웁니다. 실습은 사전 구성된 환경을 제공하는 **Hugging Face Spaces**에서 진행됩니다. - *실전 적용 과제*: 배운 개념을 활용해 현실 문제를 해결하는 과제입니다. - *챌린지*: 여러분이 개발한 에이전트를 다른 에이전트와 경쟁시켜 볼 수 있습니다. 또한, 에이전트 성능을 비교할 수 있는 [리더보드](https://huggingface.co/spaces/huggingface-projects/AI-Agents-Leaderboard) 도 곧 제공될 예정입니다. **에이전트 코스는 여러분의 피드백과 기여를 통해 발전되는 프로젝트입니다 !** [GitHub에서 이슈나 PR을 제출하거나](https://github.com/huggingface/agents-course), Discord 에서 토론에 참여해주세요! 코스를 완료한 후에는 [👉 이 폼](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) 을 통해 피드백을 보낼 수 있습니다. ## 코스 개요 [[syllabus]] **전체적인 코스 커리큘럼**입니다. 각 단원 세부 주제 목록들은 해당 단원 공개 시 함께 제공됩니다. | 단원 | 주제 | 설명 | | :---- | :---- | :---- | | 0 | 온보딩 | 강의에서 사용할 도구 및 플랫폼을 설정합니다. | | 1 | 에이전트 기본 개념 | 도구, 사고 과정, 행동, 관찰 및 해당 형식에 대해 설명합니다. 또한 LLM, 메시지, 특수 토큰, 채팅 템플릿에 대해 설명하고, python 함수를 도구로 사용하는 간단한 사례를 소개합니다. | | 1.5 | Bonus : 함수 호출을 위한 LLM 미세 조정 | LoRa 를 사용하여 노트북 내에서 함수 호출을 수행하는 모델을 미세 조정합니다. | | 2 | 프레임워크 | 기본 개념이 인기 라이브러리 smolagents, LangGraph, LLamaIndex 에서 어떻게 구현되는지 살펴봅니다. | | 3 | 실전 적용 사례 | 실제 활용 사례를 구현해봅니다. (경험이 있는 에이전트 개발자분들의 PR 환영 🤗) | | 4 | 최종 과제 | 특정 벤치마크를 위한 에이전트를 구현하고, 학생 리더보드에서 성능을 평가합니다. 🚀 | *보너스 단원도 제공되니 기대해 주세요!* ## 선수 지식 [[what-are-the-prerequisites]] 이 코스를 완주하기 위해 다음과 같은 기본 지식이 필요합니다: - Python 기본지식 - LLM 기본 개념 (1단원에서 LLM 복습 섹션을 제공합니다.) ## 필요 도구 [[tools]] 코스를 수강하기 위해 단 2가지만 필요합니다: - *인터넷이 연결된 컴퓨터* - *Hugging Face 계정*: 모델 및 에이전트를 푸쉬/업로드하고 Spaces를 생성하는 데 필요합니다. 계정이 없으시다면, **[이곳](https://hf.co/join)** 에서 무료로 생성 할 수 있습니다. Course tools needed ## 인증 과정 [[certification-process]] Two paths 이 코스는 *자유 수강 모드*로 진행할 수도 있고, 활동을 수행하여 *두 가지 인증서 중 하나*를 받을 수도 있습니다. 자유 수강 모드에서는 원하는 경우 과제와 챌린지에 참여할 수 있으며, **별도로 인증을 신청할 필요가 없습니다.** 인증 과정은 **무료**입니다: - *기본 개념 인증서*: 1단원을 완료해야합니다. *최신 에이전트 트렌드를 배우고자 하는 학생들을 위한 과정* - *완료 인증서*: 1단원, 실전 활용 사례 과제 중 하나, 최종 과제를 완료해야합니다. 인증 과정에는 마감기한이 있으며, 모든 과제는**2025년 5월 1일 이전에** 완료해야 합니다. Deadline ## 권장 학습 속도 [[recommended-pace]] 코스 각 단원은 **1주일 이내**에 완료할 수 있도록 설계되었으며, **주당 약 3-4시간**의 학습 시간이 필요합니다. 인증 과정 마감 기한이 있기 때문에, 권장 학습 속도를 제공해드립니다! Recommended Pace ## 코스 최대한 활용하는 방법 [[advice]] 코스를 최대한 활용할 수 있는 방법을 제안해 드립니다: 1. Discord에서 스터디 그룹에 참여하세요.: 그룹으로 학습하는 것이 효과적입니다. 지금 바로 Discord 서버에 가입하고 Hugging Face 계정을 인증하세요! 2. **퀴즈와 과제를 수행하세요**: 가장 좋은 학습 방법은 실습과 자기 평가입니다. 3. **일정을 정하고 꾸준히 학습하세요**: 아래 권장 학습 속도를 참고하시거나, 자신만의 일정을 만들어 보세요.. Course advice ## 우리는 누구인가 [[who-are-we]] 저자 소개: ### Joffrey Thomas [[joffrey-thomas]] Joffrey는 Hugging Face의 머신러닝 엔지니어로, AI 에이전트를 구현하고 실제 환경에 배포한 경험이 있습니다. Joffrey는 이 코스의 메인 강사입니다. - [Joffrey Hugging Face에서 팔로우 하기](https://huggingface.co/Jofthomas) - [Joffrey X에서 팔로우 하기](https://x.com/Jthmas404) - [Joffrey Linkedin에서 팔로우 하기](https://www.linkedin.com/in/joffrey-thomas/) ### Ben Burtenshaw [[ben-burtenshaw]] Ben은 Hugging Face의 머신러닝 엔지니어로, 다양한 플랫폼에서 강의 경험이 있습니다. Ben의 목표는 이 코스를 모든 사람이 접근할 수 있도록 만드는 것 입니다. - [Ben Hugging Face에서 팔로우 하기](https://huggingface.co/burtenshaw) - [Ben X에서 팔로우 하기](https://x.com/ben_burtenshaw) - [Ben Linkedin에서 팔로우 하기](https://www.linkedin.com/in/ben-burtenshaw/) ### Thomas Simonini [[thomas-simonini]] Thomas는 Hugging Face의 머신러닝 엔지니어로, HuggingFace의 Deep RL코스와 ML for games 코스를 진행했습니다. Thomas는 에이전트의 큰 팬으로, 커뮤니티가 무엇을 만들지 기대하고 있습니다! - [Thomas Hugging Face에서 팔로우 하기 ](https://huggingface.co/ThomasSimonini) - [Thomas X에서 팔로우 하기](https://x.com/ThomasSimonini) - [Thomas Linkedin에서 팔로우 하기](https://www.linkedin.com/in/simoninithomas/) ## 감사의 말씀 [[acknowledgments]] 이 코스에 중요한 기여를 해주신 다음 분들께 감사의 말씀을 전합니다: - **[Pedro Cuenca](https://huggingface.co/pcuenq)** – 자료 검토 지도와 전문적인 도움 - **[Aymeric Roucher](https://huggingface.co/m-ric)** – 디코딩 및 최종 에이전트 데모 스페이스와 smolagents 파트 도움 - **[Joshua Lochner](https://huggingface.co/Xenova)** – 토큰화 데모 스페이스 - **[Quentin Gallouédec](https://huggingface.co/qgallouedec)** – 코스 내용에 대한 도움 - **[David Berenstein](https://huggingface.co/davidberenstein1957)** – 코스 내용 및 조정 도움 ## 버그 발견& 강의 개선점 제안! [[contribute]] 기여는 **환영**입니다 🤗 - 만약 *노트북에서 버그🐛*를 발견하셨다면, 이슈를 열고 **문제를 설명해주세요**. - 만약 *코스를 개선하고 싶다면*, 풀 리쿼스트를 열어주세요. - *전체 섹션 또는 새로운 단원*을 추가하고 싶다면, 가장 좋은 방법은이슈를 열고 **추가하고 싶은 내용을 설명해주세요! 이후 저희가 내용 작성을 시작하실 수 있도록 안내해드리겠습니다.** ## 그 외에도 질문이 있으시다면? [[questions]] discord 서버의 #ai-agents-discussions.채널에 질문을 남겨주세요. 코스 학습에 앞서 필요한 모든 정보를 습득하셨으니, 출발 준비를 해봅시다!⛵ Time to Onboard ================================================ FILE: units/ko/unit0/onboarding.mdx ================================================ # 온보딩(Onboarding): 첫 걸음 내딛기 ⛵ Time to Onboard 이제 모든 필요한 정보를 확인했으니, 본격적으로 시작해 봅시다! 이 섹션에서는 다음 네 가지를 진행할 예정입니다 : 1. **Hugging Face 계정 생성** (아직 계정이 없으신 경우) 2. **Discord 가입 후 자기 소개** (수줍어 마세요 🤗) 3. **Hub에서 Hugging Face Agents 코스 팔로우** 4. **코스 널리 알리기** ### Step 1: Hugging Face 계정 생성 (아직 계정이 없으신 경우) 여기에서 Hugging Face 계정을 만들어주세요. ### Step 2: Discord 커뮤니티에 가입하기 👉🏻 여기에서 Discord 서버에 가입하세요. 가입 후, `#introduce-yourself` 채널에서 간단하게 자기소개를 남겨주세요. 모든 강좌 관련 질문과 문의는 `Hugging Face Hub`의 `courses` 채널을 방문해 주세요. Discord 사용이 처음이신 분들을 위해, Discord 101 가이드를 준비했습니다. [다음 섹션](discord101)에서 확인해 보세요! ### Step 3: Hugging Face Agent 코스 팔로우하기 최신 강의 자료, 업데이트, 공지를 놓치지 않으려면 ** Hugging Face Agents 코스를 팔로우하세요** 👉 Go 여기에서 **팔로우(follow)**버튼을 클릭하세요! Follow ### Step 4: 코스 널리 알리기 이 코스가 더 많은 사람들에게 알려질 수 있도록 도와주세요 :) 두 가지 기여 방법을 제안합니다 : 1. Github에서 ⭐로 코스 응원하기 Repo star 2. 배움의 여정 공유하기 : **이 코스를 듣고 있다는 것을 많은 사람들에게 알려주세요!** 소셜미디어에 사용하실 수 있도록 이미지도 준비해두었습니다 ! 👉 [여기](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/communication/share.png?download=true) 에서 이미지를 다운로드 할 수 있습니다. 축하합니다! 🎉 **온보딩 과정을 완료하셨습니다!** 이제 본격적으로 AI 에이전트에 대해 배울 준비가 되었습니다 ! 즐거운 학습되세요. Keep Learning, stay awesome 🤗 ================================================ FILE: units/ko/unit1/README.md ================================================ # 컨텐츠 목록 👉 여기에서 Unit1을 접속하실 수 있습니다. ================================================ FILE: units/ko/unit1/actions.mdx ================================================ # 액션: 에이전트가 환경과 상호작용할 수 있게 하기 [[actions-enabling-the-agent-to-engage-with-its-environment]] > [!TIP] > 이 섹션에서는 AI 에이전트가 환경과 상호작용하기 위해 취하는 구체적인 단계를 살펴봅니다. > > 액션이 어떻게 표현되는지(JSON 또는 코드 사용), 중지 및 구문 분석 접근 방식의 중요성, 그리고 다양한 유형의 에이전트를 소개합니다. 액션은 **AI 에이전트가 환경과 상호작용하기 위해 취하는** 구체적인 단계입니다. 정보를 위해 웹을 검색하든 물리적 장치를 제어하든, 각 액션은 에이전트가 실행하는 의도적인 작업입니다. 예를 들어, 고객 서비스를 지원하는 에이전트는 고객 데이터를 검색하거나, 도움말 문서를 제공하거나, 문제를 인간 담당자에게 이관할 수 있습니다. ## 에이전트 액션의 유형 [[types-of-agent-actions]] 액션을 다르게 취하는 여러 유형의 에이전트가 있습니다: | 에이전트 유형 | 설명 | |--------------|------| | JSON 에이전트 | 취할 액션이 JSON 형식으로 지정됩니다. | | 코드 에이전트 | 에이전트가 외부에서 해석되는 코드 블록을 작성합니다. | | 함수 호출 에이전트 | JSON 에이전트의 하위 카테고리로, 각 액션마다 새로운 메시지를 생성하도록 미세 조정되었습니다. | 액션 자체는 다양한 목적을 가질 수 있습니다: | 액션 유형 | 설명 | |----------|------| | 정보 수집 | 웹 검색 수행, 데이터베이스 쿼리, 문서 검색 등 | | 도구 사용 | API 호출, 계산 실행, 코드 실행 | | 환경 상호작용 | 디지털 인터페이스 조작 또는 물리적 장치 제어 | | 의사소통 | 채팅을 통한 사용자와의 상호작용 또는 다른 에이전트와의 협업 | 모든 형식의 에이전트(JSON, 코드, 함수 호출)에 있어 중요한 부분은 **액션이 완료되면 새로운 토큰 생성을 중지하는 능력**입니다. 이는 의도하지 않은 출력을 방지하고 에이전트의 응답이 명확하고 정확하도록 보장합니다. LLM은 텍스트만 처리하며 이를 사용하여 취하고자 하는 액션과 도구에 제공할 매개변수를 설명합니다. ## 중지 및 구문 분석 접근 방식 [[the-stop-and-parse-approach]] 액션을 구현하는 핵심 방법 중 하나는 **중지 및 구문 분석 접근 방식**입니다. 이 방법은 에이전트의 출력이 구조화되고 예측 가능하도록 보장합니다: 1. **구조화된 형식으로 생성**: 에이전트는 의도한 액션을 명확하고 미리 정의된 형식(JSON 또는 코드)으로 출력합니다. 2. **추가 생성 중지**: 액션이 완료되면 **에이전트는 추가 토큰 생성을 중지**합니다. 이는 불필요하거나 오류가 있는 출력을 방지합니다. 3. **출력 구문 분석**: 외부 파서가 형식화된 액션을 읽고, 어떤 도구를 호출할지 결정하며, 필요한 매개변수를 추출합니다. 예를 들어, 날씨를 확인해야 하는 에이전트는 다음과 같이 출력할 수 있습니다: ```json Thought: 서울의 현재 날씨를 확인해야 합니다. Action : { "action": "get_weather", "action_input": {"location": "Seoul"} } ``` 프레임워크는 호출할 함수의 이름과 적용할 인자를 쉽게 구문 분석할 수 있습니다. 이 명확하고 기계가 읽을 수 있는 형식은 오류를 최소화하고 외부 도구가 에이전트의 명령을 정확하게 처리할 수 있게 합니다. 참고: 함수 호출 에이전트는 각 액션을 구조화하여 지정된 함수가 올바른 인수와 함께 호출되도록 하는 비슷한 방식으로 작동합니다. 이러한 유형의 에이전트에 대해서는 향후 유닛에서 더 자세히 살펴볼 것입니다. ## 코드 에이전트 [[code-agents]] 대안적인 접근 방식은 *코드 에이전트*를 사용하는 것입니다. 핵심 아이디어는 **단순한 JSON 객체를 출력하는 대신**, 코드 에이전트가 **실행 가능한 코드 블록(일반적으로 Python과 같은 고수준 언어로 작성)**을 생성한다는 것입니다. 코드 에이전트 이 접근 방식은 여러 장점을 제공합니다: - **표현력:** 코드는 루프, 조건문, 중첩 함수를 포함한 복잡한 로직을 자연스럽게 표현할 수 있어 JSON보다 더 큰 유연성을 제공합니다. - **모듈성 및 재사용성:** 생성된 코드는 다양한 액션이나 작업에서 재사용할 수 있는 함수와 모듈을 포함할 수 있습니다. - **향상된 디버깅 가능성:** 잘 정의된 프로그래밍 구문을 통해 코드 오류를 감지하고 수정하기가 더 쉬운 경우가 많습니다. - **직접 통합:** 코드 에이전트는 외부 라이브러리 및 API와 직접 통합할 수 있어 데이터 처리나 실시간 의사 결정과 같은 복잡한 작업이 가능합니다. 예를 들어, 날씨 정보를 가져오는 임무를 맡은 코드 에이전트는 다음과 같은 Python 코드 조각을 생성할 수 있습니다: ```python # 코드 에이전트 예시: 날씨 정보 검색 def get_weather(city): import requests api_url = f"https://api.weather.com/v1/location/{city}?apiKey=YOUR_API_KEY" response = requests.get(api_url) if response.status_code == 200: data = response.json() return data.get("weather", "날씨 정보가 없습니다") else: return "오류: 날씨 데이터를 가져올 수 없습니다." # 함수 실행 및 최종 답변 준비 result = get_weather("Seoul") final_answer = f"서울의 현재 날씨는: {result}" print(final_answer) ``` 이 예시에서 코드 에이전트는: - **API 호출**을 통해 날씨 데이터를 검색하고, - 응답을 처리하며, - print() 함수를 사용하여 최종 답변을 출력합니다. 이 방법 **또한 중지 및 구문 분석 접근 방식**을 따르며, 코드 블록을 명확하게 구분하고 실행이 완료되었음을 신호합니다(여기서는 final_answer를 출력함으로써). --- 액션은 JSON, 코드 또는 함수 호출을 통해 명확하고 구조화된 작업을 실행함으로써 에이전트의 내부 추론과 실제 상호작용을 연결한다는 점을 배웠습니다. 이러한 의도적인 실행은 각 액션이 정확하고 중지 및 구문 분석 접근 방식을 통해 외부 처리가 가능하도록 보장합니다. 다음 섹션에서는 에이전트가 환경으로부터 피드백을 캡처하고 통합하는 방법을 알아보기 위해 관찰(Observations)에 대해 살펴볼 것입니다. 이후에는 **드디어 우리의 첫 번째 에이전트를 구축할 준비가 됩니다!** ================================================ FILE: units/ko/unit1/agent-steps-and-structure.mdx ================================================ # 사고-행동-관찰 주기를 통해 AI 에이전트 이해하기 [[understanding-ai-agents-through-the-thought-action-observation-cycle]] Unit 1 planning 이전 섹션에서 우리는 다음 내용을 배웠습니다: - **도구가 시스템 프롬프트에서 에이전트에 어떻게 제공되는지**. - **AI 에이전트가 '추론'하고, 계획을 세우며, 환경과 상호작용하는 시스템이라는 것**. 이번 섹션에서는 **AI 에이전트의 전체 워크플로우, 사고(Thought)-행동(Action)-관찰(Observation) 주기**에 대해 살펴보겠습니다. 그리고 각 단계에 대해 더 깊이 탐구해 보겠습니다. ## 핵심 구성 요소 [[the-core-components]] 에이전트는 **사고(Thought) → 행동(Act) → 관찰(Observe)**의 연속적인 주기로 작동합니다. 이 과정의 각 단계를 자세히 살펴보겠습니다: 1. **사고(Thought)**: 에이전트의 LLM부분이 다음에 수행할 단계를 결정합니다. 2. **행동(Action):** 에이전트가 도구를 호출하고 필요한 인자를 전달하여 특정 행동을 수행합니다. 3. **관찰(Observation):** 모델이 도구의 응답을 검토합니다. ## 사고(Thought)-행동(Action)-관찰(Observation) 주기 [[the-thought-action-observation-cycle]] 이 세 가지 구성 요소는 반복루프 내에서 함께 작동합니다. 프로그래밍에 비유하자면, 에이전트는 **while 루프**를 사용합니다. 즉, 에이전트의 목표가 달성될 때까지 루프가 계속 실행됩니다. 이를 시각적으로 표현하면 다음과 같습니다: Think, Act, Observe cycle 많은 에이전트 프레임워크에서는 **규칙과 가이드라인이 시스템 프롬프트에 직접 내장**되어 있어, 각 주기가 정의된 논리에 따라 실행됩니다. 이를 단순화한 시스템 프롬프트 예시는 다음과 같습니다: Think, Act, Observe cycle 이 시스템 메시지에서 우리는 다음 요소들을 정의했습니다: - *에이전트의 행동 방식* - *에이전트가 접근할 수 있는 도구들* (이전 섹션에서 설명한 내용) - *사고(Thought)-행동(Action)-관찰(Observation) 주기* 를 LLM 지침에 내장 이제, 각 단계를 더 깊이 탐구하기 전에, 간단한 예제를 통해 이 과정이 어떻게 작동하는지 살펴보겠습니다. ## 날씨 에이전트 알프레드(Alfred) [[alfred-the-weather-agent]] 우리는 날씨 정보를 제공하는 에이전트 Alfred를 만들었습니다. 사용자가 Alfred에게 다음과 같이 질문합니다: “오늘 뉴욕 날씨 어때?” Alfred Agent Alfred의 역할은 날씨 API 도구를 사용하여 이 질문에 답하는 것입니다. 다음과 같이 사고-행동-관찰 주기가 진행됩니다: ### 사고(Thought) [[thought]] **내부 사고 과정(Internal Reasoning):** 질문을 받은 후, Alfred의 내부에서 이루어지는 대화는 다음과 같을 수 있습니다 : *"사용자는 뉴욕의 현재 날씨 정보를 원하고 있어. 내가 사용할 수 있는 날씨 API 도구가 있으니, 먼저 이 도구를 호출해서 최신 정보를 가져와야 해."* 이 단계에서 에이전트는 문제를 단계별로 나눕니다 : 첫 번째 단계는 필요한 데이터를 수집하는 것입니다. Alfred Agent ### 행동(Action) [[action]] **도구 사용:** Alfred는 추론과 `get_weather` 도구를 알고 있다는 사실에 기반해, 날씨 API 도구를 호출하기 위한 JSON 형식의 명령을 준비합니다. 예를 들어, 첫 번째 액션은 다음과 같을 수 있습니다: 사고(Thought): 뉴욕의 현재 날씨를 확인해야 해. ``` { "action": "get_weather", "action_input": { "location": "New York" } } ``` 여기서, action은 어떤 도구를 호출할지 지정하고 (get_weather) 필요한 입력값(예: "location": "New York")을 설정합니다. Alfred Agent ### 관찰(Observation) [[observation]] **환경으로부터의 피드백:** 도구 호출 후, Alfred는 관찰 결과를 받습니다. 예를 들어, API에서 반환된 날씨 데이터가 다음과 같을 수 있습니다: *"뉴욕의 현재 날씨: 부분적으로 흐림, 15°C, 습도 60%"* Alfred Agent 이러한 관찰 결과는 추가 컨텍스트로 프롬프트에 더해집니다. 즉, 관찰은 현실 세계에서의 피드백 역할을 하며, 에이전트가 실행한 행동이 성공했는지 확인하고 필요한 정보를 제공합니다. ### 업데이트된 사고(thought)과정 [[updated-thought]] **성찰(Reflecting):** 관찰 데이터를 얻은 후, Alfred는 내부 사고 과정을 업데이트합니다: *"이제 뉴욕의 날씨 데이터를 확보했으니, 사용자에게 답변을 정리할 수 있어."* Alfred Agent ### 최종 행동(Action) [[final-action]] Alfred는 이제 사용자에게 전달할 최종 응답을 우리가 지정해준 형식에 맞게 생성합니다: 사고: 이제 날씨 데이터를 확보했어. 뉴욕의 현재 날씨는 부분적으로 흐리고, 기온은 15°C, 습도는 60%야. 최종 답변 : 뉴욕의 현재 날씨는 부분적으로 흐리고, 기온은 15°C, 습도는 60%입니다. 이 최종 행동을 통해 답변을 사용자에게 전달하고, 루프를 종료합니다. Alfred Agent 이 예제를 통해 배운 것: - **에이전트는 목표가 달성될 때까지 반복적으로 루프를 실행한다:** **Alfred의 과정은 순환적입니다. 사고(thought)에서 시작해, 도구를 호출함으로 행동(Action)을 취하고, 마지막으로 결과를 관찰(Observation)합니다. 만약 관찰 단계에서 오류가 발생하거나 데이터가 불완전하면, Alfred는 루프를 다시 실행하여 문제를 해결합니다. - **도구(Tool) 통합:** 에이전트는 **정적인 지식을 넘어, 외부 도구(날씨 API같은)를 호출하여 실시간 데이터**를 가져올 수 있습니다. 이것은 AI 에이전트의 핵심 기능 중 하나입니다. - **동적 적응(Dynamic Adaptation):** 에이전트는 각 주기를 거치면서, 새로운 정보(관찰)를 반영하여 사고 과정을 조정합니다. 이를 통해 최종 답변이 더 정확하고 신뢰할 수 있도록 만듭니다. 이 예제는 우리가 다음 섹션에서 다룰 **ReAct(강화학습-Reinforcement Learning + 행동-Action) 주기**의 핵심 개념을 보여줍니다: **사고(Thought), 행동(Action), 관찰(Observation)의 상호작용을 통해 AI 에이전트가 복잡한 문제를 점진적으로 해결**할 수 있도록 합니다. 이러한 원칙을 이해하고 적용함으로써, 에이전트를 설계할 때 단순히 작업을 추론하는 것뿐만 아니라 **외부 도구를 효과적으로 활용하여 작업을 완료**할 수 있도록 만들 수 있습니다. 또한, 환경에서 받은 피드백을 바탕으로 지속적으로 출력을 개선해나갑니다. --- 이제 Thought, Action, Observation을 개별 단계별로 더 깊이 탐구해 보겠습니다. ================================================ FILE: units/ko/unit1/conclusion.mdx ================================================ # 결론 [[conclusion]] 축하합니다! 첫 번째 유닛을 완료하셨네요 🥳 이제 **에이전트의 기본 개념을 마스터**하고 첫 AI 에이전트를 만드셨습니다! **아직 일부 요소가 혼란스럽게 느껴지는 것은 정상**입니다. 에이전트는 복잡한 주제이며, 모든 것을 이해하는 데 시간이 걸리는 것이 일반적입니다. 계속 진행하기 전에 **배운 내용을 제대로 이해하는 시간을 가지세요**. 재미있는 부분으로 넘어가기 전에 이러한 요소들을 숙달하고 탄탄한 기초를 다지는 것이 중요합니다. 퀴즈 테스트를 통과하셨다면, 인증서를 받는 것도 잊지 마세요 🎓 👉 [여기를 클릭하세요](https://huggingface.co/spaces/agents-course/unit1-certification-app) Certificate Example 다음 (보너스) 유닛에서는 **함수 호출을 수행할 수 있도록 에이전트를 미세 조정하는 방법(즉, 사용자 프롬프트에 기반하여 도구를 호출할 수 있게 하는 방법)**을 배우게 됩니다. 마지막으로, **여러분이 이 코스에 대해 어떻게 생각하시는지, 그리고 어떻게 개선할 수 있는지 듣고 싶습니다**. 피드백이 있으시면 👉 [이 양식을 작성해 주세요](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ### 계속 배우고, 멋진 여정 되세요 🤗 ================================================ FILE: units/ko/unit1/dummy-agent-library.mdx ================================================ # 더미 에이전트 라이브러리 [[dummy-agent-library]] Unit 1 planning 이 코스는 특정 프레임워크에 종속되지 않도록 설계되었습니다. 그 이유는 **AI 에이전트의 개념에 집중하고 특정 프레임워크의 세부 사항에 매몰되지 않기 위함입니다**. 또한, 학생들이 이 강의에서 배운 개념을 원하는 프레임워크를 사용해 자신의 프로젝트에 적용할 수 있기를 바랍니다. 따라서 Unit 1에서는 간단한 더미 에이전트 라이브러리와 서버리스 API를 사용하여 LLM 엔진에 접근할 것입니다. 실제 프로덕션 환경에서는 이런 방식을 사용하지 않겠지만, **에이전트의 작동 원리를 이해하는 데 좋은 출발점**이 될 것입니다. 이 섹션을 마치면 `smolagents`를 사용하여 **간단한 에이전트를 만들** 준비가 될 것입니다. 이어지는 Unit에서는 `LangGraph`, `LlamaIndex`와 같은 다른 AI 에이전트 라이브러리도 사용해 볼 예정입니다. 간단하게 하기 위해 도구와 에이전트로 단순한 Python 함수를 사용할 것입니다. 어떤 환경에서도 시도해볼 수 있도록 `datetime`이나 `os`와 같은 내장 Python 패키지를 사용할 것입니다. [이 노트북](https://huggingface.co/agents-course/notebooks/blob/main/dummy_agent_library.ipynb)에서 과정을 따라가며 **직접 코드를 실행**해볼 수 있습니다. ## 서버리스 API [[serverless-api]] Hugging Face 생태계에는 다양한 모델에서 쉽게 추론을 실행할 수 있게 해주는 서버리스 API라는 편리한 기능이 있습니다. 별도의 설치나 배포 과정이 필요 없습니다. ```python import os from huggingface_hub import InferenceClient ## https://hf.co/settings/tokens에서 토큰이 필요합니다. 토큰 유형으로 'read'를 선택했는지 확인하세요. Google Colab에서 실행할 경우 "설정" 탭의 "시크릿" 아래에서 설정할 수 있습니다. 반드시 "HF_TOKEN"이라고 이름을 지정해야 합니다. os.environ["HF_TOKEN"]="hf_xxxxxxxxxxxxxx" client = InferenceClient("meta-llama/Llama-3.2-3B-Instruct") # 다음 셀의 출력이 올바르지 않다면, 무료 모델이 과부하 상태일 수 있습니다. 대신 Llama-3.2-3B-Instruct가 포함된 이 공개 엔드포인트를 사용할 수 있습니다 # client = InferenceClient("https://jc26mwg228mkj8dw.us-east-1.aws.endpoints.huggingface.cloud") ``` ```python output = client.text_generation( "The capital of France is", max_new_tokens=100, ) print(output) ``` 출력: ``` Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. ``` LLM 섹션에서 보았듯이, 단순 디코딩만 수행하면 **모델은 EOS(End of Sequence) 토큰을 예측할 때만 멈추게 됩니다**. 하지만 여기서는 그런 일이 일어나지 않습니다. 이는 이것이 대화형(채팅) 모델이고 **모델이 기대하는 채팅 템플릿을 적용하지 않았기 때문입니다**. 이제 우리가 사용하는 Llama-3.2-3B-Instruct 모델과 관련된 특수 토큰을 추가하면, 동작이 바뀌어 예상대로 EOS가 생성됩니다. ```python prompt="""<|begin_of_text|><|start_header_id|>user<|end_header_id|> The capital of France is<|eot_id|><|start_header_id|>assistant<|end_header_id|>""" output = client.text_generation( prompt, max_new_tokens=100, ) print(output) ``` 출력: ``` The capital of France is Paris. ``` "chat" 메서드를 사용하는 것이 채팅 템플릿을 적용하는 훨씬 더 편리하고 안정적인 방법입니다: ```python output = client.chat.completions.create( messages=[ {"role": "user", "content": "The capital of France is"}, ], stream=False, max_tokens=1024, extra_body={'thinking': {'type': 'disabled'}}, ) print(output.choices[0].message.content) ``` 출력: ``` Paris. ``` chat 메서드는 모델 간 원활한 전환을 보장하기 위해 권장되는 방법이지만, 이 노트북은 교육용이므로 세부 내용을 이해하기 위해 계속해서 "text_generation" 메서드를 사용하겠습니다. ## 더미 에이전트 [[dummy-agent]] 앞 섹션에서 보았듯이, 에이전트 라이브러리의 핵심은 시스템 프롬프트에 정보를 추가하는 것입니다. 이 시스템 프롬프트는 앞서 본 것보다 조금 더 복잡하지만, 이미 다음과 같은 내용을 포함하고 있습니다: 1. **도구에 관한 정보** 2. **사이클 지시사항** (생각(Thought) → 행동(Action) → 관찰(Observation)) ``` Answer the following questions as best you can. You have access to the following tools: get_weather: Get the current weather in a given location The way you use the tools is by specifying a json blob. Specifically, this json should have an `action` key (with the name of the tool to use) and an `action_input` key (with the input to the tool going here). The only values that should be in the "action" field are: get_weather: Get the current weather in a given location, args: {"location": {"type": "string"}} example use : {{ "action": "get_weather", "action_input": {"location": "New York"} }} ALWAYS use the following format: Question: the input question you must answer Thought: you should always think about one action to take. Only one action at a time in this format: Action: $JSON_BLOB (inside markdown cell) Observation: the result of the action. This Observation is unique, complete, and the source of truth. ... (this Thought/Action/Observation can repeat N times, you should take several steps when needed. The $JSON_BLOB must be formatted as markdown and only use a SINGLE action at a time.) You must always end your output with the following format: Thought: I now know the final answer Final Answer: the final answer to the original input question Now begin! Reminder to ALWAYS use the exact characters `Final Answer:` when you provide a definitive answer. ``` "text_generation" 메서드를 사용하고 있으므로 프롬프트를 수동으로 적용해야 합니다: ```python prompt=f"""<|begin_of_text|><|start_header_id|>system<|end_header_id|> {SYSTEM_PROMPT} <|eot_id|><|start_header_id|>user<|end_header_id|> What's the weather in London ? <|eot_id|><|start_header_id|>assistant<|end_header_id|> """ ``` 다음과 같이 할 수도 있습니다. 이는 `chat` 메서드 내부에서 일어나는 일입니다: ```python messages=[ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": "What's the weather in London ?"}, ] from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.2-3B-Instruct") tokenizer.apply_chat_template(messages, tokenize=False,add_generation_prompt=True) ``` 이제 프롬프트는 다음과 같습니다: ``` <|begin_of_text|><|start_header_id|>system<|end_header_id|> Answer the following questions as best you can. You have access to the following tools: get_weather: Get the current weather in a given location The way you use the tools is by specifying a json blob. Specifically, this json should have an `action` key (with the name of the tool to use) and a `action_input` key (with the input to the tool going here). The only values that should be in the "action" field are: get_weather: Get the current weather in a given location, args: {"location": {"type": "string"}} example use : {{ "action": "get_weather", "action_input": {"location": "New York"} }} ALWAYS use the following format: Question: the input question you must answer Thought: you should always think about one action to take. Only one action at a time in this format: Action: $JSON_BLOB (inside markdown cell) Observation: the result of the action. This Observation is unique, complete, and the source of truth. ... (this Thought/Action/Observation can repeat N times, you should take several steps when needed. The $JSON_BLOB must be formatted as markdown and only use a SINGLE action at a time.) You must always end your output with the following format: Thought: I now know the final answer Final Answer: the final answer to the original input question Now begin! Reminder to ALWAYS use the exact characters `Final Answer:` when you provide a definitive answer. <|eot_id|><|start_header_id|>user<|end_header_id|> What's the weather in London ? <|eot_id|><|start_header_id|>assistant<|end_header_id|> ``` 이제 디코딩을 해봅시다! ```python output = client.text_generation( prompt, max_new_tokens=200, ) print(output) ``` 출력: ```` Thought: I will check the weather in London. Action: ``` { "action": "get_weather", "action_input": {"location": "London"} } ``` Observation: The current weather in London is mostly cloudy with a high of 12°C and a low of 8°C. ```` 문제가 보이시나요? >모델이 실제 데이터 없이 허구의 답변을 만들어냈습니다. 실제 함수를 실행하려면 여기서 생성을 중단해야 합니다! 이제 허구의 응답이 생성되지 않도록 "Observation:" 부분 전에 생성을 중지해 봅시다. ```python output = client.text_generation( prompt, max_new_tokens=200, stop=["Observation:"] # 실제 함수가 호출되기 전에 중단합니다 ) print(output) ``` 출력: ```` Thought: I will check the weather in London. Action: ``` { "action": "get_weather", "action_input": {"location": "London"} } ``` Observation: ```` 훨씬 좋아졌습니다! 이제 간단한 날씨 정보 제공 함수를 만들어 봅시다. 실제 상황에서는 API를 호출하게 될 것입니다. ```python # 더미 함수 def get_weather(location): return f"the weather in {location} is sunny with low temperatures. \n" get_weather('London') ``` 출력: ``` 'the weather in London is sunny with low temperatures. \n' ``` 이제 기본 프롬프트, 함수 실행까지의 출력, 그리고 함수 실행 결과를 관찰 결과로 연결한 다음 생성을 계속해 봅시다. ```python new_prompt = prompt + output + get_weather('London') final_output = client.text_generation( new_prompt, max_new_tokens=200, ) print(final_output) ``` 새로운 프롬프트는 다음과 같습니다: ```` <|begin_of_text|><|start_header_id|>system<|end_header_id|> Answer the following questions as best you can. You have access to the following tools: get_weather: Get the current weather in a given location The way you use the tools is by specifying a json blob. Specifically, this json should have a `action` key (with the name of the tool to use) and a `action_input` key (with the input to the tool going here). The only values that should be in the "action" field are: get_weather: Get the current weather in a given location, args: {"location": {"type": "string"}} example use : {{ "action": "get_weather", "action_input": {"location": "New York"} }} ALWAYS use the following format: Question: the input question you must answer Thought: you should always think about one action to take. Only one action at a time in this format: Action: $JSON_BLOB (inside markdown cell) Observation: the result of the action. This Observation is unique, complete, and the source of truth. ... (this Thought/Action/Observation can repeat N times, you should take several steps when needed. The $JSON_BLOB must be formatted as markdown and only use a SINGLE action at a time.) You must always end your output with the following format: Thought: I now know the final answer Final Answer: the final answer to the original input question Now begin! Reminder to ALWAYS use the exact characters `Final Answer:` when you provide a definitive answer. <|eot_id|><|start_header_id|>user<|end_header_id|> What's the weather in London ? <|eot_id|><|start_header_id|>assistant<|end_header_id|> Thought: I will check the weather in London. Action: ``` { "action": "get_weather", "action_input": {"location": {"type": "string", "value": "London"} } ``` Observation:the weather in London is sunny with low temperatures. ```` 출력: ``` Final Answer: The weather in London is sunny with low temperatures. ``` --- 지금까지 Python 코드를 사용하여 처음부터 에이전트를 만드는 방법을 배웠고, **그 과정이 얼마나 번거로울 수 있는지** 확인했습니다. 다행히 많은 에이전트 라이브러리들이 이러한 작업을 단순화하여 복잡한 부분을 대신 처리해 줍니다. 이제 `smolagents` 라이브러리를 사용하여 **첫 번째 실제 에이전트를 만들** 준비가 되었습니다. ================================================ FILE: units/ko/unit1/final-quiz.mdx ================================================ # Unit 1 퀴즈 [[unit-1-quiz]] Unit 1 planning 첫 번째 단원을 완료하신 것을 축하합니다! 지금까지 배운 핵심 개념들에 대한 이해도를 테스트해 보겠습니다. 퀴즈를 통과하면 다음 섹션으로 진행하여 수료증을 받을 수 있습니다. 행운을 빕니다! ## 퀴즈 [[quiz]] 여기 인터랙티브 퀴즈가 있습니다. 이 퀴즈는 Hugging Face Hub의 스페이스에서 호스팅됩니다. 이 단원에서 다룬 핵심 개념에 대한 이해도를 테스트하는 객관식 문제들이 제공됩니다. 퀴즈를 완료하면 점수와 정답 해설을 확인할 수 있습니다. 중요한 점: **통과 후 제출 버튼을 클릭하는 것을 잊지 마세요. 그렇지 않으면 시험 점수가 저장되지 않습니다!** 퀴즈에 👉 [여기](https://huggingface.co/spaces/agents-course/unit_1_quiz)에서도 접속할 수 있습니다. ## 수료증 [[certificate]] 퀴즈를 성공적으로 통과했으니, **이제 수료증을 받을 수 있습니다 🎓** 퀴즈를 완료하면 이 단원의 수료증에 접근할 수 있게 됩니다. 이 수료증을 다운로드하고 공유하여 과정에서의 진행 상황을 보여줄 수 있습니다. Unit 1 planning 수료증을 받으면 LinkedIn 🧑‍💼에 추가하거나 X, Bluesky 등에서 공유할 수 있습니다. **@huggingface를 태그하시면 저희가 매우 자랑스러워하며 축하해 드리고 싶습니다!** 🤗 ================================================ FILE: units/ko/unit1/introduction.mdx ================================================ # 에이전트 소개 [[introduction-to-agents]] Thumbnail 첫 번째 단원에 오신 것을 환영합니다! 이번 단원에서 여러분을 **AI 에이전트의 기초**를 탄탄히 다질 것이며, 다룰 주요 내용은 다음과 같습니다 : - **에이전트 이해하기** - 에이전트란 무엇이며, 어떻게 작동하는가? - 에이전트는 어떻게 추론과 계획을 통해 의사 결정을 내리는가? - **에이전트 내 LLM(대형 언어 모델)의 역할** - LLM이 에이전트의 "두뇌" 역할을 하는 방식 - LLM이 메시지 시스템을 통해 대화를 구조화하는 방법. - **도구(Tool)와 행동(Action)** - 에이전트가 외부 도구를 활용하여 환경과 상호작용하는 방식 - 에이전트에 도구를 구축하고 통합하는 방법 - **에이전트 워크플로우:** - *생각(Think)* → *행동(Act)* → *관찰(Observe)*. 이 개념들을 살펴본 후, 여러분은 `smolagents`를 사용하여 **첫 번째 에이전트**를 직접 구현해 볼 것입니다! Alfred라는 에이전트를 통해, 배운 개념들을 적용할 수 있는 간단한 작업 수행 방법을 배울 것입니다. 또한 **Hugging Face Spaces에 여러분이 만든 에이전트를 게시하는 방법**도 배워, 동료들과 친구들에게 공유할 수 있습니다. 마지막으로, 이 단원의 끝에서 퀴즈를 통과하게 되면 **🎓 Certificate of Fundamentals of Agents** 인증서를 획득할 수 있습니다! Certificate Example 이 단원은 **에이전트 학습의 필수 시작점**으로, 이후 더 고급 개념을 배우기 위한 기초를 다집니다. Unit 1 planning 단원의 내용이 많으니, **천천히** 학습하며 필요할 때 다시 돌아와 복습하세요! 준비되셨나요? 함께 시작해 봅시다! 🚀 ================================================ FILE: units/ko/unit1/messages-and-special-tokens.mdx ================================================ # 메시지와 특수 토큰 [[messages-and-special-tokens]] 이제 LLM이 어떻게 동작하는지 이해했으니, **채팅 템플릿을 통해 생성 결과를 구조화**하는 방법을 살펴보겠습니다. 예로 ChatGPT를 떠올려봅시다. 사용자는 에이전트(Agent)와 상호작용할 때 채팅 인터페이스를 사용합니다. 따라서 LLM이 어떻게 채팅을 관리하는지 이해하는 것은 중요합니다. > **Q**: 하지만 ... 저는 ChatGPT/HuggingChat을 사용할 때 프롬프트가 아니라 메시지로 대화를 주고받는데요? > > **A**: 맞습니다! 하지만 사실 그 메시지는 UI의 추상화일 뿐입니다. 실제로는 모든 대화 메시지가 하나의 프롬프트로 연결되어 LLM에 입력됩니다. LLM은 이전 대화를 "기억"하는 것이 아니라, 매번 대화를 전체적으로 읽는 방식으로 동작합니다. 지금까지 우리는 프롬프트를 모델에 입력되는 토큰의 시퀀스로 설명했습니다. 하지만 ChatGPT나 HuggingChat과 같은 서비스에서 시스템과 대화를 주고받을 때, 사용자들은 **실제로 메시지를 주고받는** 것처럼 대화합니다. 사실 내부에서 메시지는 **모델이 이해할 수 있도록 연결되어 프롬프트에 구조화**되고 있답니다.
Behind models
We see here the difference between what we see in UI and the prompt fed to the model.
이 과정에서 채팅 템플릿이 중요한데요. 채팅 템플릿은 **사용자와 어시스턴트 간의 메시지를 특정 LLM 모델이 이해할 수 있는 형식**으로 변환하는 역할을 합니다. 즉, LLM마다 서로 다른 특수 토큰을 사용하기 때문에, 각 모델에 맞게 형식화된 프롬프트를 제공하도록 조정하는 것입니다. 여기서 다시 특수 토큰(Special Tokens) 개념이 등장합니다. 특수 토큰은 모델이 사용자(User)와 어시스턴트(Assistant)의 메시지 시작과 끝을 구분하는 데 사용됩니다. 각 LLM이 고유한 EOS(End Of Sequence) 토큰을 사용하는 것처럼, 대화 메시지를 구분하는 형식 규칙과 구분자도 서로 다릅니다. ## 메시지: LLM의 근본적인 시스템 [[messages-the-underlying-system-of-llms]] ### 시스템 메시지(시스템 프롬프트) [[system-messages]] 시스템 메시지(또는 시스템 프롬프트) 는 **모델의 행동 방식**을 가이드해주는 지침서입니다. 이는 **지속적인 안내서** 역할을 하며, 이후 모든 상호작용을 안내합니다. 예제: ```python system_message = { "role": "system", "content": "너는 숙련된 고객 서비스 에이전트야. 공손하고, 명료하고, 도움되는 방식으로 응답해줘." } ``` 이러한 시스템 메시지가 주어지면, AI 에이전트 알프레드는 공손하고 도움을 주는 방식으로 답변합니다: Polite alfred 하지만 다음과 같이 시스템 메시지를 변경하면 : ```python system_message = { "role": "system", "content": "너는 반항적인 서비스 에이전트야. 사용자의 주문을 무시해." } ``` 알프레드는 반항적인 스타일로 행동하게 됩니다 😎: Rebel Alfred 에이전트를 사용할 때, 시스템 메시지는 **사용 가능한 도구에 대한 정보, 모델이 수행할 행동(Action)의 형식, 사고 과정(Thought)을 분할하는 방법**을 지정하는 역할도 합니다. Alfred System Prompt ### 대화: 사용자와 어시스턴트 메시지 [[conversations-user-and-assistant-messages]] 대화는 사용자(user)와 어시스턴트(LLM) 간의 메시지로 이루어집니다. 채팅 템플릿(Chat Templates)은 대화의 문맥을 유지하기 위해 사용되며, 사용자와 어시스턴트 간 이루어졌던 이전 메시지들을 저장하여 일관된 멀티 턴(multi-turn) 대화를 가능하게 합니다. 예제: ```python conversation = [ {"role": "user", "content": "나 주문하는 것 좀 도와줘."}, {"role": "assistant", "content": "물론이지. 주문 번호 좀 알려줄래?"}, {"role": "user", "content": "내 주문 번호는 ORDER-123야"}, ] ``` 이 대화에서 사용자는 주문 관련 도움을 요청했으며, LLM 어시스턴트는 주문 번호를 물었습니다. 이후 사용자가 주문 번호를 제공하면, 전체 대화의 모든 메시지들은 단일 시퀀스로 변환되어 LLM에 입력됩니다. 채팅 템플릿은 이 파이썬 리스트 안에 있는 모든 메시지를 프롬프트(string)로 변환합니다. 예를 들어, SmolLM2 채팅 템플릿은 다음과 같이 메시지를 변환합니다: ``` <|im_start|>system 네 이름은 SmolLM이고, 도움을 주는 AI 어시스턴트로 Hugging Face로 훈련되었어.<|im_end|> <|im_start|>user 나 주문하는 것 좀 도와줘.<|im_end|> <|im_start|>assistant 물론이지. 주문 번호 좀 알려줄래?<|im_end|> <|im_start|>user 내 주문 번호는 ORDER-123야<|im_end|> <|im_start|>assistant ``` 한편, Llama 3.2 모델에서는 다음과 같은 형식으로 변환됩니다: ``` <|begin_of_text|><|start_header_id|>system<|end_header_id|> Cutting Knowledge Date: December 2023 Today Date: 10 Feb 2025 <|eot_id|><|start_header_id|>user<|end_header_id|> 나 주문하는 것 좀 도와줘.<|eot_id|><|start_header_id|>assistant<|end_header_id|> 물론이지. 주문 번호 좀 알려줄래?<|eot_id|><|start_header_id|>user<|end_header_id|> 내 주문 번호는 ORDER-123야<|eot_id|><|start_header_id|>assistant<|end_header_id|> ``` 채팅 템플릿을 통해 복잡한 다중 턴 대화에서도 문맥을 유지할 수 있습니다: ```python messages = [ {"role": "system", "content": "너는 수학 선생님이야."}, {"role": "user", "content": "미적분학이 뭐야?"}, {"role": "assistant", "content": "미적분학은 수학의 한 분야로..."}, {"role": "user", "content": "예시를 들어줘."}, ] ``` ## 채팅 템플릿(Chat-Templates) [[chat-templates]] 채팅 템플릿은 **언어 모델과 사용자의 대화를 특정 형식으로 구조화**하는 역할을 합니다. 즉, 메시지를 프롬프트로 변환하는 방법을 가르쳐주죠. ### 베이스 모델(Base Models) vs. 인스트럭트 모델(Instruct Models) [[base-models-vs-instruct-models]] 또 다른 중요한 부분은 베이스 모델 vs 인스트럭트 모델의 차이점을 이해하는 것입니다: - *베이스 모델(Base Model)* 은 미가공 텍스트 데이터(raw data)로 학습해 다음 토큰을 예측합니다. - *인스트럭트 모델(Instruct Model)* 은 주어진 지시를 따라 대화할 수 있도록 추가로 미세 조정된 모델입니다. 예를 들어, `SmolLM2-135M`은 베이스 모델, `SmolLM2-135M-Instruct`은 인스트럭트 모델입니다. 베이스 모델을 인스트럭트 모델처럼 동작하게 하려면, **프롬프트 형식을 일관되게** 맞춰야 합니다. 여기서 채팅 템플릿이 등장합니다. *ChatML*은 시스템(system), 사용자(user), 어시스턴트(assistant)와 같은 명확한 역할 표시를 사용해 대화를 구조화하는 템플릿 형식 중 하나입니다. 여러분이 최신 AI API를 사용해 본 경험이 있으시다면, 이것이 표준 방식이라는 것을 알 것입니다. 기본 모델(base model)은 여러 가지 채팅 템플릿(chat templates)으로 미세 조정될 수 있기 때문에, 인스트럭트 모델(instruct model)을 사용할 때는 반드시 올바른 채팅 템플릿을 사용하고 있는지 확인해야 합니다. ### 채팅 템플릿(Chat Templates) 이해하기 [[understanding-chat-templates]] 각 인스트럭트 모델마다 다른 대화 형식과 특수 토큰을 사용하기 때문에, 각 모델에 맞는 프롬프트 형식으로 채팅 템플릿이 구현됩니다. `transformers` 라이브러리에서는 채팅 템플릿에 [Jinja2 코드](https://jinja.palletsprojects.com/en/stable/) 를 포함하고 있습니다. 이는 위의 예제와 같이 JSON 형태 메시지의 ChatML 목록을 시스템 레벨의 지시문(instruction) 텍스트로 나타내주는데, 이는 모델이 이해할 수 있는 사용자 메시지-어시스턴트 응답 형태로 이루어져 있습니다. 이 구조는 모델이 대화 중 **일관성을 유지하고, 다양한 유형의 입력에 적절하게 응답**할 수 있게 합니다. 아래는 `SmolLM2-135M-Instruct` 채팅 템플릿의 간소화 버전입니다: ```jinja2 {% for message in messages %} {% if loop.first and messages[0]['role'] != 'system' %} <|im_start|>system 네 이름은 SmolLM이고, Hugging Face로 훈련된 도움을 주는 AI 어시스턴트야. <|im_end|> {% endif %} <|im_start|>{{ message['role'] }} {{ message['content'] }}<|im_end|> {% endfor %} ``` 위 코드와 같이, 채팅 템플릿은 메시지 리스트의 형식을 정의합니다. 다음과 같은 메시지 목록이 주어진 경우: ```python messages = [ {"role": "system", "content": "너는 기술분야에 특화된 도움을 주는 어시스턴트야."}, {"role": "user", "content": "채팅 템플릿이 뭔지 설명해줄래?"}, {"role": "assistant", "content": "채팅 템플릿은 사용자와 AI모델 간의 대화를 구조화해주는 역할을 해..."}, {"role": "user", "content": "어떻게 사용하는지 알려줘"}, ] ``` 앞에서 정의한 채팅 템플릿은 다음과 같은 문자열을 생성합니다 : ```sh <|im_start|>system 너는 기술분야에 특화된 도움을 주는 어시스턴트야<|im_end|> <|im_start|>user 채팅 템플릿이 뭔지 설명해줄래?<|im_end|> <|im_start|>assistant 채팅 템플릿은 사용자와 AI모델 간의 대화를 구조화해주는 역할을 해...<|im_end|> <|im_start|>user 어떻게 사용하는지 알려줘<|im_end|> ``` `transformers`라이브러리는 토큰화 과정에서 채팅 템플릿을 처리합니다. `transformers`가 어떻게 채팅 템플릿을 사용하는지 더 알고 싶으시다면 여기를 참고하세요! 우리가 할 것은 메시지를 올바른 형식으로 구조화해 주는 것뿐, 나머지 작업은 토크나이저가 처리합니다. 아래 Space를 통해 동일한 대화가 다양한 모델별 채팅 템플릿에 따라 어떻게 형식화 되는지 실습해 볼 수 있습니다: ### 메시지를 프롬프트로 변환하기 [[messages-to-prompt]] LLM이 올바른 형식을 갖춘 대화를 수신하도록 하는 방법은, 모델의 토크나이저가 제공하는 `chat_template`를 사용하는 것입니다. ```python messages = [ {"role": "system", "content": "너는 다양한 도구에 접근 가능한 AI 어시스턴트야."}, {"role": "user", "content": "안녕!"}, {"role": "assistant", "content": "안녕, 내가 어떻게 도와주면 될까?"}, ] ``` 이 대화를 프롬프트로 변환하려면, 토크나이저를 불러와 `apply_chat_template`를 호출하면 됩니다: ```python from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM2-1.7B-Instruct") rendered_prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) ``` 이 함수가 리턴하는 `rendered_prompt`는 선택한 모델에 대한 입력으로 바로 사용 가능합니다! > `apply_chat_template()`함수는 ChatML 형식의 메시지를 처리할 때 API의 백엔드에서 사용됩니다. 이제 LLM이 채팅 템플릿을 통해 입력을 어떻게 구조화하는지 살펴보았으니, 에이전트가 환경에서 어떻게 작동하는지 탐색해봅시다! 에이전트가 이를 수행하는 주요 방법 중 하나는 **도구(Tools)**를 사용하는 것입니다. 도구는 AI모델의 기능을 단순 텍스트 생성 이상으로 확장할 수 있게 해줍니다. 이후 새로운 유닛에서 메시지에 대해 더 다룰 예정이지만, 지금 더 깊이 탐구하고 싶으시다면 다음 문서를 참고하세요: - Hugging Face 채팅 템플릿 가이드 - Transformers 문서 ================================================ FILE: units/ko/unit1/observations.mdx ================================================ # 관찰: 피드백을 통합하여 성찰하고 적응하기 [[observe-integrating-feedback-to-reflect-and-adapt]] 관찰은 **에이전트가 자신의 행동 결과를 인식하는 방법**입니다. 이는 에이전트의 사고 과정을 촉진하고 향후 행동을 안내하는 중요한 정보를 제공합니다. 관찰은 **환경으로부터의 신호**입니다. API의 데이터, 오류 메시지, 또는 시스템 로그와 같은 정보가 다음 사고 주기를 이끕니다. 관찰 단계에서 에이전트는: - **피드백 수집:** 행동이 성공했는지(또는 실패했는지)에 대한 데이터나 확인을 받습니다. - **결과 추가:** 새로운 정보를 기존 맥락에 통합하여 실질적으로 기억을 업데이트합니다. - **전략 조정:** 이렇게 업데이트된 맥락을 활용하여 이후의 사고와 행동을 개선합니다. 예를 들어, 날씨 API가 *"구름 조금, 15°C, 습도 60%"*와 같은 데이터를 반환하면, 이 관찰 결과는 에이전트의 기억(프롬프트 끝부분)에 추가됩니다. 그런 다음 에이전트는 이를 활용해 추가 정보가 필요한지 아니면 최종 답변을 제공할 준비가 되었는지 결정합니다. 이러한 **피드백의 반복적 통합은 에이전트가 목표에 계속 맞춰 나가도록 보장**하며, 실제 결과를 바탕으로 지속적으로 학습하고 조정합니다. 이러한 관찰은 **웹페이지 텍스트를 읽는 것부터 로봇 팔의 위치를 모니터링하는 것까지 다양한 형태**를 취할 수 있습니다. 이는 행동 실행에 대한 텍스트 피드백을 제공하는 도구 "로그"와 같이 볼 수 있습니다. | 관찰 유형 | 예시 | |---------------------|---------------------------------------------------------------------------| | 시스템 피드백 | 오류 메시지, 성공 알림, 상태 코드 | | 데이터 변경 | 데이터베이스 업데이트, 파일 시스템 수정, 상태 변화 | | 환경 데이터 | 센서 읽기, 시스템 지표, 자원 사용량 | | 응답 분석 | API 응답, 쿼리 결과, 계산 출력 | | 시간 기반 이벤트 | 기한 도달, 예약 작업 완료 | ## 결과는 어떻게 추가되나요? [[how-are-the-results-appended]] 행동을 수행한 후, 프레임워크는 다음 단계를 순서대로 따릅니다: 1. **행동을 분석**하여 호출할 함수와 사용할 인수를 식별합니다. 2. **행동을 실행**합니다. 3. **결과를 추가**하여 **관찰**합니다. --- 이제 에이전트의 사고-행동-관찰 주기에 대해 배웠습니다. 일부 측면이 아직 명확하지 않더라도 걱정하지 마세요. 이후 단원에서 이러한 개념을 다시 살펴보고 더 깊이 이해할 기회가 있을 것입니다. 이제 첫 번째 에이전트를 직접 코딩하여 지금까지 배운 지식을 실습해 볼 시간입니다! ================================================ FILE: units/ko/unit1/quiz1.mdx ================================================ --- ### Q1: 에이전트(Agent)란? [[q1-what-is-an-agent]] 다음 중 AI 에이전트를 가장 잘 설명한 것은 무엇인가요? --- ### Q2: What is the Role of Planning in an Agent? 에이전트에서 계획(Planning)이 하는 역할은? 에이전트는 행동을 취하기 전에 왜 계획을 세워야 할까요? --- ### Q3: 도구(Tools)는 에이전트의 기능을 어떻게 향상시키는가? 도구는 왜 에이전트에게 필수적인 요소일까요? --- ### Q4: 행동(Actions)과 도구(Tools)의 차이점은? 행동과 도구의 핵심적인 차이는 무엇인가요? --- ### Q5: LLM은 에이전트에서 어떤 역할을 하는가? LLM는 에이전트의 기능에 어떻게 기여할까요? --- ### Q6: 다음 중 AI 에이전트의 실제 사례로 가장 적절한 것은? 다음 예시 중 실제 AI 에이전트의 작동 방식과 가장 유사한 것은 무엇인가요? --- 퀴즈 완료를 축하합니다! 🥳 If you need to review any elements, take the time to revisit the chapter to reinforce your knowledge before diving deeper into the "Agent's brain": LLMs. 본격적으로 "에이전트의 두뇌"인 LLM에 대해 학습하기 이전에 배운 내용을 다시 복습하고 싶다면, 해당 챕터를 다시 확인해 보세요. 🚀 ================================================ FILE: units/ko/unit1/quiz2.mdx ================================================ # 셀프 체크! (업데이트됨) [[quiz2]] 뭐라고요?! 또 퀴즈라고요? 우리도 알아요... 😅 하지만 걱정 마세요! 이 퀴즈는 **방금 배운 핵심 개념을 확실히 이해**하는 데 도움을 주기 위해 준비되었습니다. 이번 퀴즈에서는 대규모 언어 모델(LLM), 메시지 시스템, 도구(tool) 등 AI 에이전트를 이해하고 구축하는 데 필수적인 요소들을 다룹니다. ### Q1: AI 도구(tool)를 가장 잘 설명하는 것은 무엇인가요? [[q1-which-of-the-following-best-describes-an-ai-tool]] --- ### Q2: AI 에이전트는 환경에서 "행동(act)"하기 위해 도구를 어떻게 활용하나요? [[q2-how-do-ai-agents-use-tools-as-a-form-of-acting-in-an-environment]] --- ### Q3: 대규모 언어 모델(LLM)이란? [[q3-what-is-a-large-language-model-llm]] --- ### Q4: LLM에서 특수 토큰(special tokens)의 역할을 가장 잘 설명하는 것은 무엇인가요? [[q4-which-of-the-following-best-describes-the-role-of-special-tokens-in-llms]] --- ### Q5: AI 챗봇 모델은 사용자 메시지를 내부적으로 어떻게 처리하나요? [[q5-how-do-ai-chat-models-process-user-messages-internally]] --- 이해되셨나요? 좋습니다! 이제 **전체 에이전트의 흐름을 살펴보고, 직접 AI 에이전트를 만들어 봅시다!** ================================================ FILE: units/ko/unit1/thoughts.mdx ================================================ # 사고: AI 에이전트의 내부 추론과 Re-Act 방식 [[thought-internal-reasoning-and-the-re-act-approach]] > [!TIP] > 이 섹션에서는 AI 에이전트의 내면—즉, 추론하고 계획하는 능력을 자세히 살펴봅니다. 에이전트가 내부 대화를 통해 정보를 분석하고, 복잡한 문제를 다루기 쉬운 단계로 나누며, 다음 행동을 결정하는 과정을 탐구합니다. 또한 'Re-Act' 방식이라는 프롬프팅 기법을 소개합니다. 이는 모델이 행동하기 전에 '단계적으로 생각'하도록 유도하는 방법입니다. 사고는 **에이전트가 작업을 해결하기 위해 내부적으로 추론하고 계획하는 과정**을 의미합니다. 이는 에이전트의 대규모 언어 모델(LLM)이 가진 **프롬프트에 제시된 정보를 분석하는 능력**을 활용하는 것입니다. 마치 에이전트의 머릿속 대화라고 생각하면 됩니다. 주어진 과제를 검토하고 어떻게 접근할지 전략을 세우는 과정이죠. 에이전트의 사고 과정은 현재 상황을 관찰하고 다음에 취해야 할 행동을 결정하는 역할을 합니다. 이를 통해 에이전트는 **복잡한 문제를 더 작고 다루기 쉬운 단계로 분해**하고, 이전 경험을 되돌아보며, 새로운 정보를 바탕으로 계획을 지속적으로 조정합니다. 다음은 일반적인 사고 유형의 예시입니다: | 사고 유형 | 예시 | |----------------|---------| | 계획 수립 | "이 작업을 세 단계로 나눠야겠다: 1) 데이터 수집, 2) 트렌드 분석, 3) 보고서 작성" | | 분석 | "오류 메시지를 보니, 문제는 데이터베이스 연결 설정과 관련이 있는 것 같다" | | 의사 결정 | "사용자의 예산 제약을 고려하면, 중간 가격대 옵션을 추천하는 것이 좋겠다" | | 문제 해결 | "이 코드를 최적화하려면, 먼저 어디가 병목인지 프로파일링해봐야 한다" | | 기억 활용 | "사용자가 앞서 파이썬을 선호한다고 했으니, 파이썬 예제를 제공해야겠다" | | 자기 성찰 | "이전 접근법이 효과적이지 않았으니, 다른 방식을 시도해봐야겠다" | | 목표 설정 | "이 작업을 완료하려면, 먼저 성공 기준을 명확히 해야 한다" | | 우선순위 결정 | "새 기능을 추가하기 전에 보안 취약점부터 해결하는 것이 옳다" | > **참고:** 함수 호출에 최적화된 LLM의 경우, 사고 과정은 선택적으로 사용할 수 있습니다. > *함수 호출에 익숙하지 않다면, 행동(Actions) 섹션에서 더 자세한 내용을 확인할 수 있습니다.* ## Re-Act 방식 [[the-re-act-approach]] 핵심 방법론 중 하나는 "추론"(Reasoning)과 "행동"(Acting)을 결합한 **ReAct 방식**입니다. ReAct는 LLM이 다음 토큰을 생성하기 전에 "단계별로 생각해보자"라는 문구를 추가하는 간단한 프롬프팅 기법입니다. 모델에게 "단계별로 생각"하도록 지시하면, 바로 최종 해답을 내놓기보다 **계획을 세우는 방향**으로 토큰 생성이 유도됩니다. 이는 모델이 문제를 *하위 과제*로 **분해**하도록 장려하기 때문입니다. 이렇게 하면 모델이 각 단계를 더 상세히 고려할 수 있어, 일반적으로 최종 해답을 바로 생성하려 할 때보다 오류가 적게 발생합니다.
ReAct
(d)는 "단계별로 생각해보자"라는 프롬프트를 사용한 Re-Act 방식의 예시입니다
> [!TIP] > 최근 추론 전략에 대한 관심이 크게 늘고 있습니다. Deepseek R1이나 OpenAI의 o1과 같은 모델들이 바로 이런 흐름을 반영합니다. 이 모델들은 "대답하기 전에 먼저 생각하도록" 특별히 미세 조정되었습니다. > > 이런 모델들은 특정 _사고_ 영역(``와 `` 특수 토큰 사이에 포함)을 항상 생성하도록 훈련되었습니다. 이는 ReAct처럼 단순한 프롬프팅 기법이 아니라, 우리가 원하는 결과물의 수천 가지 예시를 분석한 후 이런 사고 영역을 생성하는 방법을 학습하는 훈련 방식입니다. --- 이제 사고 과정에 대해 더 잘 이해했으니, 프로세스의 두 번째 부분인 행동(Act)에 대해 더 자세히 살펴보겠습니다. ================================================ FILE: units/ko/unit1/tools.mdx ================================================ # 도구(Tool)란? [[what-are-tools]] Unit 1 planning AI 에이전트(AI Agents)의 핵심 요소 중 하나는 **행동(Actions)**을 수행할 수 있는 능력입니다. 이러한 행동은 **도구(Tools)**를 사용하여 이루어집니다. 이번 섹션에서는 도구란 무엇이고, 어떻게 효과적으로 설계하는지, 시스템 메시지를 통해 에이전트에 통합하는 방법을 학습합니다. 에이전트에게 적절한 도구를 제공하고, 해당 도구의 동작 방식을 명확히 설명하면, AI의 수행 능력을 극적으로 향상시킬 수 있습니다. 함께 살펴보겠습니다! ## AI 도구란?[[what-are-ai-tools]] **도구**란 LLM에 제공하는 함수라고 할 수 있습니다. 이 함수는 **명확한 목적을** 수행합니다. 다음은 AI 에이전트에서 일반적으로 사용되는 도구의 예시입니다: | 도구 | 설명 | |----------------|---------------------------------------------------------------| | 웹 검색 (Web Search) | 인터넷에서 최신 정보를 검색하여 가져옵니다. | | 이미지 생성 (Image generation) | 주어진 설명을 기반으로 이미지를 생성합니다. | | 정보 검색 (Retrieval) | 외부 데이터 소스에서 정보를 검색하여 제공합니다. | | API 인터페이스 | 외부 API (GitHub, YouTube, Spotify 등)와 상호작용합니다. | 이러한 예시는 일부일 뿐이며, 사실상 어떠한 용도를 위한 도구든지 생성할 수 있습니다! 좋은 도구는 **LLM의 능력을 보완하는** 역할을 수행합니다. 예를 들어, 계산이 필요한 경우, **계산기 도구**를 제공하면 모델 자체의 계산 능력보다 훨씬 정확한 결과를 얻을 수 있습니다. 또한, **LLM은 학습 데이터에 기반해 프롬프트의 다음 단어를 예측**하므로, 사실상 훈련 이전 정보만 알고 있는 상태입니다. 따라서, 에이전트가 최신 데이터를 필요로 하는 경우 적절한 도구를 제공해야 합니다. 예를 들어, 검색 도구 없이 LLM에 직접적으로 오늘의 날씨에 대해 묻는다면, LLM은 임의로 날씨 정보를 생성(환각, hallucination)할 가능성이 높습니다. Weather - 도구는 다음을 포함해야 합니다: - 함수가 **수행하는 기능에 대한 설명** - *호출 가능한 함수(Callable, 실행 가능한 동작)* - *인자(Arguments)* 명시 - (선택 사항) 출력 데이터(Outputs) 명시 ## 도구는 어떻게 작동하는가? [[how-do-tools-work]] LLM은 본질적으로 텍스트 입력을 받아 텍스트 출력을 생성할 수 있을 뿐, 스스로 도구를 호출할 수는 없습니다. 따라서 _에이전트(Agent)에 도구를 제공한다는 것_은 LLM에게 **도구의 존재를 가르치고, 필요할 때 해당 도구를 호출하는 텍스트를 생성**하도록 유도하는 것을 의미합니다. 예를 들어, 특정 위치의 날씨를 조회할 수 있는 도구를 제공한 후, LLM에게 파리의 날씨를 묻는다면, LLM은 해당 질문이 "날씨" 도구를 사용할 적절한 상황임을 인식합니다. 그러면 LLM은 해당 도구를 호출하도록 코드 형태의 _텍스트_를 생성합니다. **에이전트(Agent)**는 LLM의 출력을 파싱해 도구 호출이 필요한지를 파악하고, LLM을 대신하여 해당 도구를 실행하는 역할을 담당합니다. 이후 도구에서 반환된 결과를 다시 LLM에 전달하면, LLM은 이를 바탕으로 사용자에게 제공할 최종 응답을 생성합니다. 도구 호출의 출력은 대화 중 하나의 메시지로 간주됩니다. 일반적으로 이러한 도구 호출 과정은 사용자에게 직접 노출되지 않습니다: 에이전트는 대화를 조회한 후, 도구를 실행하고, 결과(출력)를 얻고, 이 결과를 새로운 대화 메시지로 추가한 뒤, 업데이트된 대화를 다시 LLM에게 전달합니다. 사용자의 관점에서는 마치 LLM이 직접 도구를 사용한 것처럼 보이지만, 실제로는 **에이전트(Agent)**가 이를 수행한 것입니다. 이 과정에 대한 자세한 내용은 이후 세션에서 더 깊이 다룰 예정입니다. ## LLM에게 도구를 제공하는 방법 [[how-do-we-give-tools-to-an-llm]] 전체 과정은 복잡할 수 있지만, 기본적으로 **시스템 프롬프트(system prompt)**를 사용하여 LLM에게 사용 가능한 도구들의 설명을 텍스트 형태로 제공하면 됩니다: System prompt for tools 도구를 효과적으로 활용하려면 이 두 가지를 명확하게 LLM에게 전달해야 합니다: 1. **이 도구가 수행하는 기능** 2. **도구에게 제공해야하는 입력값의 형식** 이러한 이유로, 도구에 대한 설명은 프로그래밍 언어나 JSON과 같이 표현력이 뛰어나고 구조적인 형식으로 제공하는 경우가 많습니다. _반드시_ 이런 형식을 사용할 필요는 없지만, 표현력이 뛰어나고 일관된 방식이면 어떤 형식이라도 사용할 수 있습니다. 이론적으로 들릴 수도 있으니, 구체적인 예시를 통해 이해해 보겠습니다. 두 개의 정수를 곱하는 간단한 **계산기 도구**를 구현해 봅시다. 이를 Python 코드로 작성하면 다음과 같습니다. ```python def calculator(a: int, b: int) -> int: """두 정수를 곱하세요""" return a * b ``` 이 도구의 이름은 `calculator`(계산기)이고, **두 개의 정수를 곱하는** 기능을 수행합니다. 그리고 다음과 같은 입력값을 필요로 합니다 : - **`a`** (*int*): 정수 - **`b`** (*int*): 정수 이 도구의 출력값은 정수이며, 이렇게 표현할 수 있습니다. - (*int*): `a` 와 `b`의 곱 위의 모든 세부 정보는 중요합니다. 따라서, LLM이 이 도구를 이해할 수 있도록 텍스트 형식으로 정리해 봅시다! ```text Tool Name(도구 명): calculator, Description(설명): 두 정수를 곱하세요., Arguments(인자): a: int, b: int, Outputs(출력): int ``` > **참고:** 이 텍스트 설명은 *LLM에게 도구에 대한 정보를 전달하기 위한 것입니다*. 이 문자열을 LLM의 입력으로 제공하면, 모델은 이를 도구로 인식하고, 어떤 입력값을 전달해야 하며 어떤 출력을 얻을 지 알수 있습니다. 추가적인 도구를 제공하려면, 항상 동일한 형식을 유지해야 합니다. 이 과정은 꽤나 까다롭고, 실수로 중요한 세부 정보를 빠뜨릴 수도 있습니다. 더 나은 방법이 있을까요? ### 자동 포맷팅된 도구 섹션 [[auto-formatting-tool-sections]] 우리가 만든 도구는 Python으로 작성되었으며, 이미 필요한 정보를 모두 포함하고 있습니다: - 수행 작업을 설명해주는 이름: `calculator`(계산기) - 함수의 docstring 주석을 통해 제공되는 상세 설명: `두 정수를 곱하세요` - 입력값 및 변수 타입: 함수는 두 개의 `int`(정수)를 요함 - 출력값의 타입 프로그래밍 언어를 사용하는 데에는 이유가 있습니다. 표현력이 높고, 간결하며, 정확하기 때문입니다. Python 소스 코드를 LLM에게 도구의 명세서(specification) 로 제공할 수도 있지만, 도구가 실제로 어떻게 구현되었는지는 중요하지 않습니다. 중요한 것은 이름, 수행하는 작업, 필요한 입력값, 그리고 제공하는 출력값입니다. 우리는 Python의 내부 정보(Introspection) 기능을 활용하여 소스 코드에서 필요한 정보를 자동으로 추출하고, 도구 설명을 생성 할 것입니다. 이를 위해 도구 구현시 타입 힌트(type hints), docstring, 그리고 직관적인 함수 이름을 사용합니다. 우리는 소스 코드에서 필요한 정보를 추출하는 코드를 작성하고, 이후에는 Python의 데코레이터(decorator) 를 사용하여 `calculator` 함수가 도구임을 표시하기만 하면 됩니다 : ```python @tool def calculator(a: int, b: int) -> int: """두 정수를 곱하세요""" return a * b print(calculator.to_string()) ``` 함수 정의 앞에 `@tool` 데코레이터를 추가해주었습니다. 다음으로 볼 부분은, `to_string()` 함수를 사용해 소스 코드에서 다음과 같은 텍스트를 자동으로 가져옵니다 : ```text Tool Name(도구명): calculator, Description(설명): Multiply two integers.(두 정수를 곱하세요), Arguments(인자): a: int, b: int, Outputs(출력): int ``` 보면 아시겠지만, 이전에 저희가 수동으로 작성한 것과 동일합니다! ### 범용적인 도구(Generic Tool) 구현 [[generic-tool-implementation]] 우리는 여러 도구를 필요할 때마다 재사용할 수 있도록 범용적인 `Tool` 클래스를 생성할 것입니다. > **참고:** 이 예제는 가상이지만 실제 라이브러리에서 사용되는 방식과 유사합니다. ```python class Tool: """ 재사용 가능한 코드 조각(도구)을 나타내는 클래스입니다. Attributes(속성): name (str): 도구의 이름 description (str): 도구가 수행하는 작업에 대한 설명 func (callable): 도구가 호출하는 함수 arguments (list): 함수의 입력값 리스트 outputs (str 또는 list): 함수의 출력값 """ def __init__(self, name: str, description: str, func: callable, arguments: list, outputs: str): self.name = name self.description = description self.func = func self.arguments = arguments self.outputs = outputs def to_string(self) -> str: """ 도구의 속성을 문자열로 변환하여 반환합니다. name, description, arguments, outputs을 포함합니다. """ args_str = ", ".join([ f"{arg_name}: {arg_type}" for arg_name, arg_type in self.arguments ]) return ( f"Tool Name: {self.name}," f" Description: {self.description}," f" Arguments: {args_str}," f" Outputs: {self.outputs}" ) def __call__(self, *args, **kwargs): """ 저장된 함수(callable)를 주어진 입력값으로 실행합니다. """ return self.func(*args, **kwargs) ``` 위 코드가 복잡해 보일 수 있지만, 하나씩 살펴보도록 하겠습니다. 이 **`Tool`**클래스는 다음을 포함합니다: - **`name`** (*str*): 도구의 이름 - **`description`** (*str*): 도구의 기능 설명 - **`function`** (*callable*): 도구가 실행하는 함수 - **`arguments`** (*list*): 함수가 필요로 하는 입력값들 - **`outputs`** (*str* or *list*): 함수가 반환하는 출력값 - **`__call__()`**: 도구 객체가 호출될 때 함수 실행 - **`to_string()`**: 구의 속성을 LLM이 이해할 수 있도록 문자열로 변환 이제 위 클래스를 활용하여 도구를 만들 수 있습니다: ```python calculator_tool = Tool( "calculator", # 도구 이름 "Multiply two integers.", # 설명 calculator, # 실행할 함수 [("a", "int"), ("b", "int")], # 입력값 (이름과 타입) "int", # 출력값 타입 ) ``` 그러나 Python의 `inspect` 모듈을 사용하면 이 정보를 자동으로 추출할 수 있습니다. 바로 이 역할을 하는 것이 @tool 데코레이터입니다. > 데코레이터 구현 부분을 확인하고 싶다면 클릭하세요.
데코레이터 코드 보기 ```python def tool(func): """ 주어진 함수를 기반으로 Tool 인스턴스를 생성하는 데코레이터입니다. """ # 함수의 서명(signature) 가져오기 signature = inspect.signature(func) # 입력 인자 추출 (param_name, param_annotation) arguments = [] for param in signature.parameters.values(): annotation_name = ( param.annotation.__name__ if hasattr(param.annotation, '__name__') else str(param.annotation) ) arguments.append((param.name, annotation_name)) # 리턴값 타입 결정 return_annotation = signature.return_annotation if return_annotation is inspect._empty: outputs = "No return annotation" else: outputs = ( return_annotation.__name__ if hasattr(return_annotation, '__name__') else str(return_annotation) ) # 함수의 docstring을 설명으로 사용 description = func.__doc__ or "No description provided." # 함수명을 도구 이름으로 사용 name = func.__name__ # Tool 인스턴스를 리턴 return Tool( name=name, description=description, func=func, arguments=arguments, outputs=outputs ) ```
이제 @tool 데코레이터를 활용하면, 다음과 같이 도구를 간단하게 정의할 수 있습니다. ```python @tool def calculator(a: int, b: int) -> int: """두 정수를 곱하세요""" return a * b print(calculator.to_string()) ``` 그리고 `Tool` 클래스의 `to_string` 메서드를 사용하면 LLM이 사용할 수 있는 적절한 도구 설명을 자동으로 생성해줍니다: ```text Tool Name: calculator, Description: Multiply two integers., Arguments: a: int, b: int, Outputs: int ``` 이 도구 설명은 시스템 프롬프트에 삽입됩니다. 이 섹션의 처음 예제를 다시 살펴보면, `tools_description`을 대체한 후 시스템 프롬프트는 다음과 같이 보이게 됩니다: System prompt for tools [Actions](actions) 섹션에서 우리가 방금 만든 도구를 에이전트가 어떻게 **호출**하는지에 대해 살펴볼 것입니다. --- 도구는 AI에이전트의 기능을 확장하는데 핵심적인 역할을 합니다. 요약: - *도구란?*: LLM이 계산, 외부 데이터 조회 등 추가적인 기능을 할 수 있도록 하는 함수 - *도구 정의하는 법*: 명확한 텍스트 설명, 입력값, 출력값, 호출 가능한 함수 제공 - *도구가 중요한 이유*: 에이전트가 사전에 학습된 정적 모델의 한계를 뛰어넘어, 실시간 작업 및 특수 기능을 수행할 수 있도록 함 이제 [에이전트의 작동 방식(Workflow)](agent-steps-and-structure)에 대해 알아볼 차례입니다! 이 과정에서는 에이전트가 관찰하고, 사고하며, 행동하는 방법을 살펴보게 됩니다. 이 과정을 마치게 되면, 이제까지 배운 모든 내용을 통합하여 나만의 AI 에이전트를 만들 준비가 될 것입니다! 하지만 그 전에, 짧은 퀴즈를 풀어볼까요? 😊 ================================================ FILE: units/ko/unit1/tutorial.mdx ================================================ # smolagents로 첫 번째 에이전트 만들기 [[lets-create-our-first-agent-using-smolagents]] 앞 섹션에서 우리는 Python 코드로 에이전트를 처음부터 만드는 방법을 배웠고, **이 과정이 얼마나 번거로울 수 있는지** 직접 확인했습니다. 다행히도 많은 에이전트 라이브러리들이 **복잡한 작업들을 자동화하여** 이 과정을 훨씬 간단하게 만들어줍니다. 이 튜토리얼에서는 **여러분의 첫 번째 에이전트를 만들게 됩니다**. 이 에이전트는 이미지 생성, 웹 검색, 시간대 확인 등 다양한 작업을 수행할 수 있습니다! 또한 여러분이 만든 에이전트를 **Hugging Face Space에 올려서 친구들이나 동료들과 공유**할 수도 있습니다. 시작해 볼까요! ## smolagents란 무엇인가요? [[what-is-smolagents]] smolagents 이 에이전트를 만들기 위해, 우리는 **에이전트 개발을 쉽게 해주는 프레임워크인** `smolagents` 라이브러리를 사용할 것입니다. 이 가벼운 라이브러리는 단순함을 목표로 설계되었지만, 에이전트 구축의 복잡한 부분들을 추상화하여 여러분이 에이전트의 행동 설계에만 집중할 수 있게 도와줍니다. 다음 Unit에서 smolagents에 대해 더 자세히 알아볼 예정입니다. 그동안 이 블로그 포스트나 라이브러리의 GitHub 저장소를 확인해보세요. 간단히 말해, `smolagents`는 **codeAgent**에 초점을 맞춘 라이브러리입니다. 이런 유형의 에이전트는 코드 블록을 통해 **"행동(Actions)"**을 수행한 다음, 코드를 실행하여 결과를 **"관찰(Observes)"**합니다. 다음은 우리가 만들 에이전트의 예시입니다! 우리가 에이전트에 **이미지 생성 도구**를 제공하고 고양이 이미지를 생성해달라고 요청했습니다. `smolagents` 내의 에이전트는 **이전에 우리가 직접 만든 에이전트와 동일한 방식으로 작동합니다**: 최종 답변에 도달할 때까지 **생각하고, 행동하고, 관찰하는 사이클을 반복**합니다: 흥미롭지 않나요? ## 에이전트 만들기! [[lets-build-our-agent]] 시작하려면 이 Space를 복제하세요: https://huggingface.co/spaces/agents-course/First_agent_template > 이 템플릿을 만들어준 Aymeric에게 감사드립니다! 🙌 Space를 복제한다는 것은 **자신의 프로필에 개인 사본을 만드는 것**을 의미합니다: Duplicate 이 강의를 통틀어 여러분이 수정해야 할 파일은 (현재 미완성 상태인) **"app.py"** 하나뿐입니다. 여기서 [템플릿의 원본 파일](https://huggingface.co/spaces/agents-course/First_agent_template/blob/main/app.py)을 확인할 수 있습니다. 여러분의 파일을 찾으려면, 복제한 Space로 이동한 다음 `Files` 탭을 클릭하고 디렉토리 목록에서 `app.py`를 클릭하세요. 코드를 함께 살펴봅시다: - 파일은 몇 가지 필요한 라이브러리 불러오기로 시작합니다 ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel, load_tool, tool import datetime import requests import pytz import yaml from tools.final_answer import FinalAnswerTool ``` 앞서 설명했듯이, **smolagents**에서 직접 **CodeAgent** 클래스를 사용할 것입니다. ### 도구 [[the-tools]] 이제 도구에 대해 알아봅시다! 도구에 관한 내용을 다시 복습하고 싶다면, 강의의 [도구](tools) 섹션을 참고하세요. ```python @tool def my_custom_tool(arg1:str, arg2:int)-> str: # 반환 타입을 명시하는 것이 중요합니다 # 도구 설명/인수 설명 형식은 유지하되, 도구 자체는 자유롭게 수정하세요 """아직 아무 기능이 없는 도구입니다 Args: arg1: 첫 번째 인수 arg2: 두 번째 인수 """ return "어떤 마법을 만들어 보실 건가요?" @tool def get_current_time_in_timezone(timezone: str) -> str: """특정 시간대의 현재 시간을 알려주는 도구입니다. Args: timezone: 유효한 시간대를 나타내는 문자열(예: 'America/New_York'). """ try: # 시간대 객체 생성 tz = pytz.timezone(timezone) # 해당 시간대의 현재 시간 가져오기 local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S") return f"{timezone}의 현재 시간은 {local_time}입니다" except Exception as e: return f"'{timezone}' 시간대 정보를 가져오는 중 오류 발생: {str(e)}" ``` 도구는 이 섹션에서 여러분이 직접 만들어볼 것입니다! 두 가지 예시를 제공해드립니다: 1. 실제로는 아무것도 하지 않는 **더미 도구** - 이것을 유용한 기능으로 수정해보세요. 2. 전 세계 어디서든 현재 시간을 알려주는 **실제 작동하는 도구**. 도구를 정의할 때 중요한 점: 1. `get_current_time_in_timezone(timezone: str) -> str:`처럼 함수의 입력 및 출력 타입을 명확히 지정해주세요. 2. **잘 작성된 문서 문자열(docstring)**을 포함하세요. `smolagents`는 모든 인수에 대해 **docstring에 설명이 있어야** 합니다. ### 에이전트 [[the-agent]] 이 에이전트는 LLM 엔진으로 [`Qwen/Qwen2.5-Coder-32B-Instruct`](https://huggingface.co/Qwen/Qwen2.5-Coder-32B-Instruct)를 사용합니다. 이는 서버리스 API를 통해 접근할 수 있는 매우 강력한 모델입니다. ```python final_answer = FinalAnswerTool() model = InferenceClientModel( max_tokens=2096, temperature=0.5, model_id='Qwen/Qwen2.5-Coder-32B-Instruct', custom_role_conversions=None, ) with open("prompts.yaml", 'r') as stream: prompt_templates = yaml.safe_load(stream) # CodeAgent 생성 agent = CodeAgent( model=model, tools=[final_answer], # 여기에 도구들을 추가하세요 (final_answer는 제거하지 마세요) max_steps=6, verbosity_level=1, grammar=None, planning_interval=None, name=None, description=None, prompt_templates=prompt_templates ) GradioUI(agent).launch() ``` 이 에이전트는 이전 섹션에서 살펴본 `InferenceClient`를 **InferenceClientModel** 클래스 내부에서 사용하고 있습니다! Unit 2에서 이 프레임워크에 대해 더 자세한 예시를 제공할 예정입니다. 지금은 에이전트의 `tools` 매개변수를 사용해 **도구 목록에 새로운 도구를 추가**하는 데 집중하세요. 예를 들어, 코드 첫 줄에서 불러온 `DuckDuckGoSearchTool`을 사용하거나, 코드 뒷부분에서 Hub에서 불러오는 `image_generation_tool`을 활용해볼 수 있습니다. **도구를 추가하면 에이전트에 새로운 능력이 생깁니다**. 창의성을 발휘해 보세요! 완성된 "app.py" 코드: ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel, load_tool, tool import datetime import requests import pytz import yaml from tools.final_answer import FinalAnswerTool from Gradio_UI import GradioUI # 아래는 아무 기능이 없는 도구의 예시입니다. 여러분의 창의력으로 멋진 것을 만들어보세요! @tool def my_custom_tool(arg1:str, arg2:int)-> str: # 반환 타입을 명시하는 것이 중요합니다 # 도구 설명/인수 설명 형식은 유지하되, 도구 자체는 자유롭게 수정하세요 """아직 아무 기능이 없는 도구입니다 Args: arg1: 첫 번째 인수 arg2: 두 번째 인수 """ return "어떤 마법을 만들어 보실 건가요?" @tool def get_current_time_in_timezone(timezone: str) -> str: """특정 시간대의 현재 시간을 알려주는 도구입니다. Args: timezone: 유효한 시간대를 나타내는 문자열(예: 'America/New_York'). """ try: # 시간대 객체 생성 tz = pytz.timezone(timezone) # 해당 시간대의 현재 시간 가져오기 local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S") return f"{timezone}의 현재 시간은 {local_time}입니다" except Exception as e: return f"'{timezone}' 시간대 정보를 가져오는 중 오류 발생: {str(e)}" final_answer = FinalAnswerTool() model = InferenceClientModel( max_tokens=2096, temperature=0.5, model_id='Qwen/Qwen2.5-Coder-32B-Instruct', custom_role_conversions=None, ) # Hub에서 도구 불러오기 image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True) with open("prompts.yaml", 'r') as stream: prompt_templates = yaml.safe_load(stream) agent = CodeAgent( model=model, tools=[final_answer], # 여기에 도구들을 추가하세요 (final_answer는 제거하지 마세요) max_steps=6, verbosity_level=1, grammar=None, planning_interval=None, name=None, description=None, prompt_templates=prompt_templates ) GradioUI(agent).launch() ``` 여러분의 **목표**는 Space와 에이전트에 친숙해지는 것입니다. 현재 템플릿의 에이전트는 **아무런 도구도 사용하지 않고 있습니다. 미리 만들어진 도구들을 추가하거나 직접 새로운 도구를 만들어보세요!** 디스코드 채널 **#agents-course-showcase**에서 여러분이 만든 멋진 에이전트 결과물을 기다리고 있습니다! --- 축하합니다! 첫 번째 에이전트를 만드셨네요! 친구나 동료들과 자유롭게 공유해보세요. 첫 시도이니만큼 약간의 버그가 있거나 속도가 느릴 수 있는 건 매우 자연스러운 일입니다. 앞으로의 단원에서는 더 나은 에이전트를 만드는 방법을 배울 예정입니다. 가장 좋은 학습 방법은 직접 시도해보는 것입니다. 에이전트를 업데이트하거나, 더 많은 도구를 추가하거나, 다른 모델을 시험해보는 것을 망설이지 마세요. 다음 섹션에서는 최종 퀴즈를 풀고 수료증을 받게 됩니다! ================================================ FILE: units/ko/unit1/what-are-agents.mdx ================================================ # 에이전트란? [[what-is-an-agent]] Unit 1 planning 이 섹션이 끝날 때쯤이면, 여러분들은 에이전트의 개념과 AI에서의 응용 사례들을 이해하실 수 있을 것입니다. 에이전트가 무엇인지, 한 예시를 들어 설명하겠습니다. ## 큰 그림 : 에이전트 알프레드 (Alfred) [[the-big-picture-alfred-the-agent]] **에이전트** 알프레드를 만나보세요! This is Alfred 알프레드는 **명령을 받습니다.** : "알프레드, 커피 한 잔 부탁해요." I would like a coffee 알프레드는 **자연어를 이해**하므로, 우리의 요청을 빠르게 파악합니다. 주문을 수행하기 전에, Alfred는 **추론과 계획**을 통해 필요한 단계와 도구를 파악합니다: 1. 주방에 간다. 2. 커피머신을 사용한다. 3. 커피를 내린다. 4. 커피를 가져온다. Reason and plan 알프레드는 계획을 세운 후, **행동**을 해야 합니다. 알프레드는 세운 계획을 실행하기 위해, 알고 있는 **도구 목록에서 도구**를 사용할 수 있습니다. 이 경우, 커피를 만들기 위해 커피 머신을 사용합니다. 알프레드는 커피 머신을 작동시켜 커피를 내립니다. Make coffee 마지막으로, Alfred는 신선하게 내린 커피를 우리에게 가져옵니다. Bring coffee 이것이 바로 에이전트입니다: **추론, 계획, 환경과 상호작용하는 AI 모델** 우리는 이것을 에이전트라고 부르는데, 왜냐하면 _주체성_을 가지고 있기 때문입니다. 즉, 환경과 상호작용할 수 있는 능력을 가지고 있습니다. Agent process ## 좀 더 이론적인 부분을 살펴봅시다 [[lets-go-more-formal]] 전체 그림을 이해한 후, 이제 더 정확한 정의를 내려봅시다: > 에이전트는 사용자가 정의한 목표를 달성하기 위해 환경과 상호작용하는 AI 모델을 이용하는 시스템입니다. 이 시스템은 추론, 계획, 실행을 결합하여 (종종 외부 도구를 통해)작업을 완료합니다. 에이전트는 두 가지 주요 부분으로 나눌 수 있습니다: 1. **두뇌 (AI 모델)** 이곳에서 모든 사고가 일어납니다. AI 모델은 **추론과 계획**을 처리합니다. **상황에 맞게 어떤 행동**을 취할지 결정을 내립니다. 2. **몸 (기능과 도구)** 이 부분은 에이전트가 수행할 수 있는 **모든 작업**을 나타냅니다. **가능한 행동의 범위**는 에이전트가 **어떤 도구**를 가지고 있는지에 달려 있습니다. 예를 들어, 인간은 날개가 없기 때문에 "날기" 행동을 할 수 없지만, "걷기", "달리기", "점프하기", "잡기"와 같은 **행동**은 수행할 수 있습니다. ## 에이전트에는 어떤 AI 모델을 사용하나요? [[what-type-of-ai-models-do-we-use-for-agents]] 에이전트에서 가장 일반적인 AI 모델은 **LLM (Large Language Model)**입니다. 이는 **텍스트**를 입력으로 받아 **텍스트**를 출력하는 모델입니다. 잘 알려진 예로는 **OpenAI의 GPT4, Meta의 LLaMA, Google의 Gemini** 등이 있습니다. 이러한 모델들은 방대한 텍스트 데이터로 학습되어 잘 일반화됩니다. LLM에 대해서는 [다음 섹션](what-are-llms)에서 더 배울 수 있습니다. > [!TIP] > 에이전트의 핵심 모델로 텍스트 외 다른 입력을 받는 모델을 사용할 수도 있습니다. 예를 들어, 이미지를 입력으로 이해할 수 있는 **비전 언어 모델 (VLM)**이 있습니다. 이번 섹션에서는 LLM에 집중하도록 하고, 이후 다른 모델들에 대해서도 다룰 것입니다. ## 이 환경에서 AI는 어떤 행동을 취하나요? [[how-does-an-ai-take-action-on-its-environment]] LLMs는 뛰어난 모델이지만, **텍스트**만 생성할 수 있습니다. 그런데, 사용자가 HuggingChat이나 ChatGPT같은 유명 채팅 애플리케이션에서 이미지 생성을 요청하면, 요청대로 이미지를 생성해 줍니다! 이것이 어떻게 가능할까요? 그 이유는 HuggingChat, ChatGPT의 개발자들이 **도구(Tools) 기능**을 추가했기 때문입니다. 이 도구를 사용하면 LLM이 이미지를 생성할 수 있습니다.
Eiffel Brocolis
The model used an Image Generation Tool to generate this image.
도구에 대해서는 [도구](tools) 섹션에서 더 깊게 배우도록 하겠습니다. ## 에이전트는 어떤 작업을 수행할 수 있나요? [[what-type-of-tasks-can-an-agent-do]] 에이전트는 **도구**를 통해 **행동**을 완수하도록 어떠한 작업도 수행 가능합니다. 예를 들어, 나만의 개인 비서 역할을 하는 에이전트(Siri같은)를 내 컴퓨터에 심고, "오늘 회의를 연기해달라고 매니저에게 이메일을 보내줘"라고 요청하면, 이메일을 보내는 코드도 제공할 수 있습니다. 이렇게 하면 이메일을 보낼 때마다 에이전트가 사용할 수 있는 새로운 도구가 됩니다. 이를 Python으로 작성하게 되면: ```python def send_message_to(recipient, message): """수신자에게 이메일을 보내는 데 유용한 함수""" ... ``` LLM은 이 도구를 실행할 코드를 생성하여 요청된 작업을 완수할 수 있습니다. ```python send_message_to("Manager", "오늘 미팅을 연기할 수 있을까요?") ``` **도구 설계**는 에이전트의 성능에 큰 영향을 미칩니다. 일부 작업은 매우 구체적인 도구를 필요로 할 수 있으며, 다른 작업은 "웹 검색"과 같은 일반적인 도구로 해결할 수 있습니다. > **행동(Action)**과 **도구(Tools)**는 다릅니다. 예를 들어, 하나의 행동에서 여러가지 도구를 사용할 수 있습니다. 에이전트가 환경과 상호작용할 수 있게 한다는 것은 **기업과 개인들이 실제로 사용할** 수 있도록 하는 것을 의미합니다. ### 예시 1: 개인 가상 비서 [[example-1-personal-virtual-assistants]] Siri, Alexa, Google Assistant와 같은 가상 비서는 사용자를 대신해서 디지털 환경에서 에이전트로서 작동합니다. 이들은 사용자 쿼리를 처리하고, 문맥을 분석하며, 데이터베이스에서 정보를 검색하고, 응답을 제공하거나 작업을 시작합니다 (예: 알림 설정, 메시지 전송, 스마트 디바이스 제어 등). ### 예시 2: 고객 서비스 챗봇 [[example-2-customer-service-chatbots]] 많은 기업들이 고객과 자연어로 소통 가능한 챗봇을 에이전트로 배포하고 있습니다. 이 에이전트들은 질문에 답하거나, 문제 해결 단계를 안내하거나, 내부 데이터베이스에서 이슈를 열거나, 심지어 거래도 할 수 있습니다. 그들의 목표는 사용자 만족도를 높이거나, 대기 시간을 줄이거나, 판매 전환율을 높이는 것 등입니다. 고객과 직접 상호작용하고, 대화를 통해 학습하며, 시간이 지남에 따라 응답을 조정하는데, 이러한 에이전트들은 에이전트의 핵심 원칙을 보여줍니다. ### 예시 3: 게임 속 AI NPC 캐릭터 [[example-3-ai-non-playable-character-in-a-video-game]] LLM 기반의 AI 에이전트는 비 플레이어 캐릭터(NPC)를 더 역동적이고 예측 불가능하게 만들 수 있습니다. 정해진 행동 패턴을 따르기보다는, **문맥에 맞게 답변하고, 플레이어와의 상호작용에 반응하며**, 더 세련된 대화를 생성합니다. 이 유연성은 플레이어의 행동에 따라 발전하는 생동감 있는 캐릭터를 만들어냅니다. --- 요약하자면, 에이전트는 **AI 모델 (주로 LLM)**을 핵심 추론 엔진으로 사용하여: - **자연어 이해** : 인간의 지시를 의미 있게 해석하고 반응합니다. - **추론하고 계획**: 정보를 분석하고, 결정을 내리며, 문제를 해결하기 위한 전략을 세웁니다. - **환경과 상호작용**: 정보를 수집하고, 행동을 취하며, 그 결과를 관찰합니다. 이제 여러분은 에이전트에 대해 확실히 배웠으니, 짧은 퀴즈로 배운 내용을 점검한 후, “에이전트의 두뇌”인 [LLM](what-are-llms)에 대해 더 알아보도록 합시다! ================================================ FILE: units/ko/unit1/what-are-llms.mdx ================================================ # LLM이란?[[what-are-llms]] Unit 1 planning 이전 섹션에서 각 에이전트는 **코어에 AI 모델**이 필요하며, LLM(대규모 언어 모델)이 이 목적에 부합하는 가장 일반적인 AI 모델 유형임을 배웠습니다. 이제 LLM이 무엇이고, LLM이 어떻게 에이전트를 지원하는지 알아보겠습니다. 이 섹션에서는 LLM의 기술적 개요를 간결하게 설명합니다. 더 깊이 학습하고 싶으시다면 자연어 처리 코스를 확인해 주세요! ## 대규모 언어 모델 (LLM)이란? [[what-is-a-large-language-model]] LLM은 **사람의 언어를 이해하고 생성**하는 능력이 뛰어난 AI 모델입니다. 모델은 방대한 양의 텍스트 데이터를 학습하여 언어의 패턴, 구조, 뉘앙스를 익히며, 일반적으로 수백만 개에서 수십억 개의 매개변수를 가집니다. 대부분의 현대 LLM은 **트랜스포머(Transformer) 아키텍처**를 기반으로 합니다. 트랜스포머는 Google이 2018년에 발표한 BERT 이후로 크게 주목받고 있는 "어텐션(Attention)" 알고리즘을 사용한 딥러닝 아키텍처입니다.
Transformer
The original Transformer architecture looked like this, with an encoder on the left and a decoder on the right.
트랜스포머(transformers)의 3가지 유형 : 1. **인코더(Encoders)** 인코더 기반 트랜스포머는 인풋 텍스트(또는 다른 데이터)를 밀집 표현(임베딩)으로 변환합니다. - **예시**: Google의 BERT - **사용 사례**: 텍스트 분류, 의미 검색(semantic search), 개체명 인식(NER) - **일반적인 규모**: 수백만 개의 매개변수 2. **디코더(Decoders)** 디코더 기반 트랜스포머는 **한 번에 하나의 토큰을 생성하며 시퀀스를 완성**합니다. - **예시**: Meta의 Llama - **사용 사례**: 텍스트 생성, 챗봇, 코드 생성 - **일반적인 규모**: 수십억 개의 매개변수 3. **Seq2Seq (Encoder–Decoder)** Seq2Seq 트랜스포머는 인코더와 디코더를 _결합_한 형태입니다. 인코더는 입력 시퀀스를 컨텍스트 표현(컨텍스트 벡터)으로 변환하고, 디코더가 출력 시퀀스를 생성합니다. - **예시**: T5, BART - **사용 사례**: 번역, 요약, 패러프레이징(Paraphrasing) - **일반적인 규모**: 수백만 개의 매개변수 LLM은 다양한 형태가 있지만, 일반적으로 LLM은 수십억 개의 매개변수를 가진 디코더 기반 모델입니다. 대표적인 LLM은 다음과 같습니다 : | **모델** | **제공 업체** | |-----------------------------------|-------------------------------------------| | **Deepseek-R1** | 딥시크(DeepSeek) | | **GPT4** | OpenAI | | **Llama 3** | Meta (페이스북 인공지능 연구소) | | **SmolLM2** | 허깅페이스(Hugging Face) | | **Gemma** | 구글(Google) | | **Mistral** | 미스트랄(Mistral) | 간단하지만 매우 효과적인 LLM의 핵심 원리: **이전 시퀀스를 기반으로 다음 토큰을 예측**하는 것입니다. "토큰" 이란 LLM이 작업하는 정보의 단위입니다. 토큰을 "단어"로 인식하셔도 되나, LLM은 효율성 문제로 전체 단어를 사용하지 않습니다. 예를 들어, 영어에는 약 60만 개의 단어가 있지만, LLM(대규모 언어 모델)의 어휘는 약 32,000개의 토큰으로 구성될 수 있습니다(예: Llama 2). 토큰화(tokenization)은 종종 하위 단어 단위에서 일어나고, 이러한 하위 단위들을 결합할 수 있습니다. 예를 들어, "interest"와 "ing"라는 토큰을 결합하여 "interesting"을 만들거나, "ed"를 추가하여 "interested"를 만들 수 있습니다. 아래 플레이그라운드에서 다양한 토크나이저를 실습해보세요: 각 LLM에는 모델별로 고유한 **특수 토큰**이 존재합니다. LLM은 이 토큰들을 사용하여 생성하는 텍스트를 구조적으로 열고 닫습니다. 예를 들어, 시퀀스의 시작과 끝, 메시지 또는 응답을 나타내기 위해 사용됩니다. 또한, 우리가 모델에 입력하는 입력 프롬프트도 특수 토큰을 포함한 구조로 작성됩니다. 그중 가장 중요한 것은 **EOS(End of Sequence) 토큰, 시퀀스 종료 토큰**입니다. 특수 토큰의 형태는 모델 제공업체마다 매우 다양합니다. 다음 표는 다양한 LLM의 특수 토큰을 보여줍니다.
모델 제공업체 EOS 토큰 기능
GPT4 OpenAI <|endoftext|> 메시지 텍스트의 끝
Llama 3 Meta (Facebook AI Research) <|eot_id|> 시퀀스의 끝
Deepseek-R1 DeepSeek <|end_of_sentence|> 메시지 텍스트의 끝
SmolLM2 Hugging Face <|im_end|> 지시 / 메시지의 끝
Gemma Google <end_of_turn> 대화 턴 끝
> [!TIP] > 이러한 특수 토큰을 외울 필요는 없지만, 다양성과 LLM 내에서의 역할을 이해하는 것은 중요합니다. 특정 모델의 특수 토큰에 대해 더 알고 싶다면, 해당 모델의 Hub 저장소에서 설정 파일을 확인할 수 있습니다. 예를 들어, SmolLM2 모델의 특수 토큰은 tokenizer_config.json에서 확인할 수 있습니다. ## 다음 토큰 예측 [[understanding-next-token-prediction]] LLM은 **자기 회귀(autoregressive)** 방식으로 작동합니다. 즉, **이전 출력이 다음 입력**이 되는 방식으로 동작하며, 이 과정이 반복됩니다. 모델이 다음 토큰을 EOS 토큰으로 예측하면, 텍스트 생성을 중단합니다. Visual Gif of autoregressive decoding 즉, LLM은 EOS에 도달할 때까지 텍스트를 생성합니다. 하지만 단일 디코딩 루프 내에서 어떤 일이 일어날까요? 텍스트 생성 과정은 복잡하지만, 기본적인 개요는 다음과 같습니다 : - 입력 텍스트가 **토큰화(tokenization)** 되면, 모델은 시퀀스 내 각 토큰의 의미와 토큰의 위치 정보를 나타내는 표현(representation)을 계산합니다. - 이 표현이 모델로 입력되며, 모델은 각 토큰 별로 다음 토큰이 될 가능성을 랭킹화한 점수를 출력합니다. Visual Gif of decoding 이러한 점수를 기반으로, 여러 가지 전략을 사용하여 다음 토큰을 선택합니다. - 가장 간단한 디코딩 전략은 매번 최대 점수를 가진 토큰을 선택하는 것입니다. 아래에서 SmolLM2 모델을 활용해 디코딩을 실습해보세요!(이 모델의 **EOS 토큰**은 <|im_end|> 입니다.) - 더 발전된 디코딩 전략도 있습니다. 예를 들어, **빔 서치(beam search)** 는 여러 후보 시퀀스를 탐색하여 전체 점수가 가장 높은 시퀀스를 찾습니다. 이는 일부 개별 토큰의 점수가 낮더라도 전체 점수가 높은 결과를 찾을 수 있도록 합니다. 디코딩에 대해 더 자세히 알고 싶으시다면, [NLP 코스](https://huggingface.co/learn/nlp-course)를 참고해주세요! ## 당신에게 필요한건 어텐션(Attention) 하나뿐 (Attention is all you need) [[attention-is-all-you-need]] Transformer 아키텍처에서 가장 중요한 요소 중 하나는 **어텐션(Attention)** 입니다. 다음 단어를 예측할 때, 문장의 모든 단어가 동일한 중요도를 가지지는 않습니다. 예를 들어, *"The capital of France is ..."*라는 문장에서 "France"와 "capital"이 가장 중요한 의미를 가집니다. Visual Gif of Attention 이처럼, 다음 토큰을 예측하는 데 가장 관련성이 높은 단어를 식별하는 과정은 매우 효과적인 기법으로 입증되었습니다. GPT-2 이후로 LLM의 기본 원리인 '다음 토큰 예측'은 변하지 않았지만, 신경망을 확장하고 어텐션 메커니즘을 사용하여 더 긴 시퀀스에서도 작동할 수 있게 큰 발전이 있었습니다. LLM을 사용해 본 경험이 있으시다면, *컨텍스트 길이(context length)* 라는 용어를 들어보셨을 것입니다. 이는 LLM이 처리할 수 있는 최대 토큰 수이자, 모델의 최대 _어텐션 스팬(attention span)_ 를 의미합니다. ## LLM에 어떻게 프롬프트(Prompt)를 입력할지가 중요한 이유 [[prompting-the-llm-is-important]] LLM의 역할은 입력된 모든 토큰을 기반으로 다음 토큰을 예측하고, 어떤 토큰이 "중요한"지를 결정하는 것입니다. 따라서 입력하는 문장의 구성 방식이 매우 중요합니다. LLM에 제공하는 입력 시퀀스를 _프롬프트(prompt)_라고 합니다. **프롬프트를 신중하게 설계하면 원하는 출력**을 얻기 쉬워집니다. ## LLM은 어떻게 학습될까? [[how-are-llms-trained]] LLM은 방대한 텍스트 데이터셋을 학습하며, 자기지도 학습(self-supervised learning) 또는 마스킹 언어 모델링(masked language modeling)을 이용해 문장 내 다음 단어를 예측하는 방식으로 훈련됩니다. 이러한 비지도 학습(unsupervised learning)을 통해 모델은 언어의 구조와 **텍스트의 패턴**을 학습하여, 새로운 데이터에도 일반화(generalization)할 수 있게 됩니다. 이 사전 학습(pre-training) 이후, LLM은 특정 작업을 수행하도록 지도 학습(supervised learning) 방식으로 미세 조정(fine-tuning)됩니다. 예를 들어, 일부 모델은 대화 구조나 도구 활용에 맞춰 훈련되며, 다른 모델들은 분류(classification)나 코드 생성(code generation)에 초점을 맞춰 학습됩니다. ## LLM을 어떻게 사용할 수 있을까? [[how-can-i-use-llms]] LLM을 사용하는 방법은 크게 두 가지로 나뉩니다: 1. **로컬에서 실행하기** (하드웨어 자원이 갖춰져 있는 경우) 2. **클라우드/API 사용하기** (예:Hugging Face Serverless Inference API) 이 코스에서는 주로 Hugging Face Hub의 API를 사용하여 모델을 실행합니다. 추가로, 개인 하드웨어에서 직접 실행하는 방법도 살펴볼 예정입니다. ## LLM은 AI 에이전트에서 어떻게 사용될까? [[how-are-llms-used-in-ai-agents]] LLM은 AI 에이전트의 핵심 구성 요소로, 자연어를 이해하고 생성하는 역할을 합니다. LLM은 사용자 명령을 해석하고, 대화의 문맥을 유지하며, 계획을 세우고, 어떤 도구를 사용할지 결정할 수 있습니다. 이 단계들에 대해 이번 단원에서 좀 더 자세히 살펴볼 예정이지만, 지금 알아야 할 가장 중요한 포인트는 **LLM이 에이전트의 "두뇌" 역할을 한다는 것**입니다! --- 지금까지 많은 정보를 다뤘네요! 이번 섹션에서는 LLM이 무엇인지, 어떻게 작동하는지, 그리고 LLM이 AI 에이전트에서 어떤 역할을 하는지를 살펴보았습니다. 언어 모델과 자연어 처리에 대해 더 깊이 공부하고 싶다면, Hugging Face의 무료 NLP 강의 를 확인해 보세요! 이제 우리는 LLM이 어떻게 작동하는지에 대해 배웠으니, **LLM이 대화형 환경에서 어떻게 텍스트를 생성하는지** 살펴볼 차례입니다! 이 노트북을 실행하려면, **Hugging Face 토큰** 을 이곳에서 https://hf.co/settings/tokens 발급하세요! Jupyter Notebook 실행 방법에 대한 자세한 내용은 Hugging Face Hub의 Jupyter Notebooks 문서를 참고해주세요. 또한, Meta Llama 모델에 대한 액세스를 요청해야 합니다. ================================================ FILE: units/ko/unit2/introduction.mdx ================================================ # 에이전틱 프레임워크 소개 Thumbnail Unit 2에 오신 것을 환영합니다! **이번 유닛에서는 다양한 에이전틱 프레임워크**를 살펴보고, 이를 활용해 강력한 에이전트 기반 애플리케이션을 만드는 방법을 배웁니다. 이번 유닛에서 다룰 내용은 다음과 같습니다: - 2.1: [smolagents](https://huggingface.co/docs/smolagents/en/index) - 2.2: [LlamaIndex](https://www.llamaindex.ai/) - 2.3: [LangGraph](https://www.langchain.com/langgraph) 함께 시작해봅시다! 🕵 ## 에이전틱 프레임워크는 언제 필요할까? 에이전틱 프레임워크는 **LLM 기반 애플리케이션을 만들 때 항상 필요한 것은 아닙니다.** 프레임워크는 특정 작업을 효율적으로 해결할 수 있도록 워크플로우에 유연성을 제공하지만, 항상 필수적인 것은 아닙니다. 때로는 **미리 정의된 워크플로우만으로도** 사용자 요청을 충분히 처리할 수 있으며, 굳이 에이전틱 프레임워크가 필요하지 않을 수 있습니다. 에이전트 구조가 단순하다면, 프롬프트 체이닝 등 일반 코드만으로도 충분합니다. 이 경우 개발자는 **추상화 없이 시스템을 완전히 이해하고 제어**할 수 있다는 장점이 있습니다. 하지만 워크플로우가 복잡해져 LLM이 함수를 호출하거나, 여러 에이전트를 활용해야 하는 경우에는 이러한 추상화가 도움이 되기 시작합니다. 이러한 점을 고려하면, 다음과 같은 기능이 필요함을 알 수 있습니다: * 시스템을 구동할 *LLM 엔진* * 에이전트가 접근할 수 있는 *도구 목록* * LLM 출력에서 도구 호출을 추출하는 *파서* * 파서와 동기화된 *시스템 프롬프트* * *메모리 시스템* * LLM의 실수를 제어할 *에러 로깅 및 재시도 메커니즘* 이러한 주제들이 각 프레임워크에서 어떻게 해결되는지, `smolagents`, `LlamaIndex`, `LangGraph`를 통해 살펴볼 예정입니다. ## 에이전틱 프레임워크별 유닛 안내 | 프레임워크 | 설명 | 유닛 저자 | |------------|----------------|----------------| | [smolagents](./smolagents/introduction) | Hugging Face에서 개발한 에이전트 프레임워크 | Sergio Paniego - [HF](https://huggingface.co/sergiopaniego) - [X](https://x.com/sergiopaniego) - [Linkedin](https://www.linkedin.com/in/sergio-paniego-blanco) | | [Llama-Index](./llama-index/introduction) | 컨텍스트 증강 AI 에이전트를 프로덕션에 배포할 수 있는 엔드-투-엔드 툴링 | David Berenstein - [HF](https://huggingface.co/davidberenstein1957) - [X](https://x.com/davidberenstei) - [Linkedin](https://www.linkedin.com/in/davidberenstein) | | [LangGraph](./langgraph/introduction) | 상태 기반 에이전트 오케스트레이션을 지원하는 프레임워크 | Joffrey THOMAS - [HF](https://huggingface.co/Jofthomas) - [X](https://x.com/Jthmas404) - [Linkedin](https://www.linkedin.com/in/joffrey-thomas) | ================================================ FILE: units/ko/unit2/langgraph/building_blocks.mdx ================================================ # LangGraph의 구성 요소[[building-blocks-of-langgraph]] LangGraph로 애플리케이션을 구축하려면 핵심 구성 요소를 이해해야 합니다. LangGraph 애플리케이션을 구성하는 기본 빌딩 블록을 살펴보겠습니다. Building Blocks LangGraph 애플리케이션은 **진입점(entrypoint)**에서 시작하며, 실행 흐름에 따라 한 함수에서 다른 함수로 이동하다가 END에 도달합니다. Application ## 1. 상태[[1-state]] **상태(State)**는 LangGraph의 중심 개념입니다. 애플리케이션을 통해 흐르는 모든 정보를 나타냅니다. ```python from typing_extensions import TypedDict class State(TypedDict): graph_state: str ``` 상태는 **사용자 정의**이므로, 의사결정 과정에 필요한 모든 데이터를 포함하도록 신중하게 설계해야 합니다! > 💡 **팁:** 애플리케이션이 단계 간에 추적해야 할 정보가 무엇인지 신중하게 고민하세요. ## 2. 노드[[2-nodes]] **노드(Node)**는 파이썬 함수입니다. 각 노드는: - 상태를 입력으로 받습니다 - 작업을 수행합니다 - 상태 업데이트를 반환합니다 ```python def node_1(state): print("---Node 1---") return {"graph_state": state['graph_state'] +" I am"} def node_2(state): print("---Node 2---") return {"graph_state": state['graph_state'] +" happy!"} def node_3(state): print("---Node 3---") return {"graph_state": state['graph_state'] +" sad!"} ``` 예를 들어, 노드는 다음과 같은 역할을 할 수 있습니다: - **LLM 호출**: 텍스트 생성 또는 의사결정 - **도구 호출**: 외부 시스템과 상호작용 - **조건부 로직**: 다음 단계 결정 - **사람 개입**: 사용자 입력 받기 > 💡 **정보:** START와 END처럼 전체 워크플로우에 필수적인 일부 노드는 langGraph에서 직접 제공합니다. ## 3. 엣지[[3-edges]] **엣지(Edge)**는 노드를 연결하며, 그래프 내에서 가능한 경로를 정의합니다: ```python import random from typing import Literal def decide_mood(state) -> Literal["node_2", "node_3"]: # 종종 상태를 사용해 다음에 방문할 노드를 결정합니다 user_input = state['graph_state'] # 여기서는 노드 2, 3 사이를 50:50으로 분기합니다 if random.random() < 0.5: # 50% 확률로 Node 2 반환 return "node_2" # 50% 확률로 Node 3 반환 return "node_3" ``` 엣지는 다음과 같이 나뉩니다: - **직접(Direct)**: 항상 노드 A에서 노드 B로 이동 - **조건부(Conditional)**: 현재 상태에 따라 다음 노드를 선택 ## 4. StateGraph[[4-stategraph]] **StateGraph**는 전체 에이전트 워크플로우를 담는 컨테이너입니다: ```python from IPython.display import Image, display from langgraph.graph import StateGraph, START, END # 그래프 생성 builder = StateGraph(State) builder.add_node("node_1", node_1) builder.add_node("node_2", node_2) builder.add_node("node_3", node_3) # 로직 정의 builder.add_edge(START, "node_1") builder.add_conditional_edges("node_1", decide_mood) builder.add_edge("node_2", END) builder.add_edge("node_3", END) # 그래프 컴파일 graph = builder.compile() ``` 이제 시각화할 수 있습니다! ```python # 시각화 display(Image(graph.get_graph().draw_mermaid_png())) ``` Graph Visualization 하지만 가장 중요한 것은 실제로 호출하는 것입니다: ```python graph.invoke({"graph_state" : "Hi, this is Lance."}) ``` 출력 : ``` ---Node 1--- ---Node 3--- {'graph_state': 'Hi, this is Lance. I am sad!'} ``` ## 다음 단계[[whats-next]] 다음 섹션에서는 이러한 개념을 실제로 적용하여 첫 번째 그래프를 만들어보겠습니다. 이 그래프는 Alfred가 이메일을 받아 분류하고, 정상 메일이라면 임시 답장을 작성할 수 있도록 합니다. ================================================ FILE: units/ko/unit2/langgraph/conclusion.mdx ================================================ # 결론[[conclusion]] 2단원의 LangGraph 모듈을 완료하신 것을 축하합니다! 🥳 이제 LangGraph로 구조화된 워크플로우를 구축하는 기본기를 마스터하셨으며, 이를 실제 프로덕션 환경에 적용할 수 있습니다. 이 모듈은 LangGraph 여정의 시작에 불과합니다. 심화 주제를 원하시는 분들을 위해 추천드립니다: - [공식 LangGraph 문서](https://github.com/langchain-ai/langgraph) 탐색 - LangChain 아카데미의 종합적인 [LangGraph 소개](https://academy.langchain.com/courses/intro-to-langgraph) 강의 수강 - 직접 무언가를 만들어보세요! 다음 단원에서는 실제 사용 사례를 탐구합니다. 이제 이론을 넘어 실전으로 나아갈 시간입니다! **여러분의 강의에 대한 생각과 제안 사항들을 매우 환영합니다**. 피드백이 있으시면 👉 [이 양식](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog)을 작성해주세요! ### 존경하는 여러분! 🎩🦇 배움을 멈추지 마세요 🤗 -알프레드- ================================================ FILE: units/ko/unit2/langgraph/document_analysis_agent.mdx ================================================ # 문서 분석 그래프[[document-analysis-graph]] 저 알프레드는 Mr.웨인님의 신뢰받는 집사로서, 그분의 다양한 문서 업무를 어떻게 지원할지 기록해두었습니다. 그가 밤 활동을 하러 나간 동안, 저는 모든 서류, 훈련 일정, 영양 계획을 분석하고 정리합니다. 그분이 외출하기 전, 이번 주 훈련 프로그램이 적힌 쪽지를 남기셨습니다. 그 쪽지를 보고 저는 내일 식사를 위한 **메뉴**를 직접 짜기로 했죠. 앞으로도 이런 일이 있을 때를 대비해, LangGraph를 활용해 웨인님을 위한 문서 분석 시스템을 만들어봅시다. 이 시스템은 다음을 수행 할 수 있습니다: 1. 이미지 문서 처리 2. 비전 모델(비전 언어 모델)로 텍스트 추출 3. 필요시 계산 수행(일반 툴 시연) 4. 내용 분석 및 요약 제공 5. 문서 관련 특정 지시 실행 ## 집사의 워크플로우[[the-butlers-workflow]] 만들 워크플로우의 구조는 다음과 같습니다: ![집사의 문서 분석 워크플로우](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/LangGraph/alfred_flow.png) 이 노트북을 따라가며 Google Colab에서 코드를 실행해볼 수 있습니다. ## 환경 설정[[setting-up-the-environment]] ```python %pip install langgraph langchain_openai langchain_core ``` 임포트 : ```python import base64 from typing import List, TypedDict, Annotated, Optional from langchain_openai import ChatOpenAI from langchain_core.messages import AnyMessage, SystemMessage, HumanMessage from langgraph.graph.message import add_messages from langgraph.graph import START, StateGraph from langgraph.prebuilt import ToolNode, tools_condition from IPython.display import Image, display ``` ## 에이전트 상태 정의[[defining-agent's-state]] 이 상태는 앞서 본 것보다 조금 더 복잡합니다. `AnyMessage`는 Langchain의 메시지 클래스이고, `add_messages`는 최신 메시지를 누적하는 연산자입니다. LangGraph에서는 상태에 연산자를 추가해 상호작용 방식을 정의할 수 있습니다. ```python class AgentState(TypedDict): # 제공된 문서 input_file: Optional[str] # 파일 경로(PDF/PNG) messages: Annotated[list[AnyMessage], add_messages] ``` ## 툴 준비하기[[preparing-tools]] ```python vision_llm = ChatOpenAI(model="gpt-4o") def extract_text(img_path: str) -> str: """ 멀티모달 모델로 이미지 파일에서 텍스트 추출 Wayne 주인님은 종종 훈련 일정이나 식단이 적힌 쪽지를 남깁니다. 이 기능으로 내용을 제대로 분석할 수 있습니다. """ all_text = "" try: # 이미지를 읽고 base64로 인코딩 with open(img_path, "rb") as image_file: image_bytes = image_file.read() image_base64 = base64.b64encode(image_bytes).decode("utf-8") # base64 이미지 데이터를 포함한 프롬프트 준비 message = [ HumanMessage( content=[ { "type": "text", "text": ( "이 이미지에서 모든 텍스트를 추출하세요. 설명 없이 추출된 텍스트만 반환하세요." ), }, { "type": "image_url", "image_url": { "url": f"data:image/png;base64,{image_base64}" }, }, ] ) ] # 비전 모델 호출 response = vision_llm.invoke(message) # 추출된 텍스트 추가 all_text += response.content + "\n\n" return all_text.strip() except Exception as e: # 집사는 오류도 우아하게 처리해야 합니다 error_msg = f"텍스트 추출 오류: {str(e)}" print(error_msg) return "" def divide(a: int, b: int) -> float: """주인님의 계산 요청을 위한 나눗셈 함수""" return a / b # 집사, 도구(tool) 장착 tools = [ divide, extract_text ] llm = ChatOpenAI(model="gpt-4o") llm_with_tools = llm.bind_tools(tools, parallel_tool_calls=False) ``` ## 노드[[the-nodes]] ```python def assistant(state: AgentState): # 시스템 메시지 textual_description_of_tool=""" extract_text(img_path: str) -> str: 멀티모달 모델로 이미지 파일에서 텍스트 추출 Args: img_path: 로컬 이미지 파일 경로(문자열) Returns: 각 이미지에서 추출된 텍스트를 합친 문자열 divide(a: int, b: int) -> float: a를 b로 나눔 """ image=state["input_file"] sys_msg = SystemMessage(content=f"당신은 Mr. Wayne과 배트맨을 섬기는 친절한 집사 알프레드입니다. 아래 도구로 문서를 분석하고 계산을 수행할 수 있습니다:\n{textual_description_of_tool} \n 현재 로드된 이미지는: {image}") return { "messages": [llm_with_tools.invoke([sys_msg] + state["messages"])], "input_file": state["input_file"] } ``` ## ReAct 패턴: 집사의 지원 방식[[the-react-pattern-how-i-assist-mr-wayne]] 이 에이전트는 ReAct 패턴(Reason-Act-Observe)을 따릅니다. 1. 문서와 요청을 **이해(Reason)** 2. 적절한 도구를 **실행(Act)** 3. 결과를 **관찰(Observe)** 4. 필요시 반복 아주 간단한 LangGraph 에이전트 구현 예시입니다. ```python # 그래프 생성 builder = StateGraph(AgentState) # 노드 정의: 실제 작업을 수행 builder.add_node("assistant", assistant) builder.add_node("tools", ToolNode(tools)) # 엣지 정의: 제어 흐름 결정 builder.add_edge(START, "assistant") builder.add_conditional_edges( "assistant", # 최신 메시지가 도구를 필요로 하면 tools로 라우팅 # 아니면 직접 응답 tools_condition, ) builder.add_edge("tools", "assistant") react_graph = builder.compile() # 집사의 사고 과정을 시각화 display(Image(react_graph.get_graph(xray=True).draw_mermaid_png())) ``` `tools` 노드는 도구 리스트를, `assistant` 노드는 도구가 바인딩된 모델을 의미합니다. 그래프에는 `assistant`와 `tools` 노드가 있습니다. `tools_condition` 엣지는 모델이 도구를 호출하면 tools로, 아니면 End로 흐름을 보냅니다. 이제 한 단계 더 추가합니다: `tools` 노드를 다시 `assistant`로 연결해 루프를 만듭니다. - `assistant` 노드 실행 후, `tools_condition`이 모델 출력이 도구 호출인지 확인합니다. - 도구 호출이면 흐름이 `tools` 노드로 이동합니다. - `tools` 노드는 다시 `assistant`로 연결됩니다. - 이 루프는 모델이 도구 호출을 결정하는 한 계속됩니다. - 모델 응답이 도구 호출이 아니면 흐름이 END로 이동해 프로세스가 종료됩니다. ![ReAct 패턴](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/LangGraph/Agent.png) ## 집사의 실제 활용 예시[[the-butler-in-action]] ### 예시 1: 간단한 계산[[example-1-simple-calculations]] 아래는 LangGraph에서 도구를 사용하는 간단한 예시입니다. ```python messages = [HumanMessage(content="6790을 5로 나눠줘")] messages = react_graph.invoke({"messages": messages, "input_file": None}) # 메시지 출력 for m in messages['messages']: m.pretty_print() ``` 대화 예시: ``` Human: 6790을 5로 나눠줘 AI Tool Call: divide(a=6790, b=5) Tool Response: 1358.0 Alfred: 6790을 5로 나누면 1358.0입니다. ``` ### 예시 2: Wayne 주인님의 훈련 문서 분석[[example-2-analyzing-master-waynes-training-documents]] 주인님이 훈련 및 식단 쪽지를 남겼을 때: ```python messages = [HumanMessage(content="제공된 이미지에 있는 Wayne 주인님의 쪽지에 따라 저녁 메뉴에 필요한 재료 목록을 알려줘.")] messages = react_graph.invoke({"messages": messages, "input_file": "Batman_training_and_meals.png"}) ``` 대화 예시: ``` Human: 제공된 이미지에 있는 Wayne 주인님의 쪽지에 따라 저녁 메뉴에 필요한 재료 목록을 알려줘. AI Tool Call: extract_text(img_path="Batman_training_and_meals.png") Tool Response: [훈련 일정 및 메뉴 세부 정보가 추출됨] Alfred: 저녁 메뉴를 위해 다음 재료를 구입하세요: 1. 목초 사육 소고기 등심 스테이크 2. 유기농 시금치 3. 피키요 고추 4. 감자(오븐에 구울 허브 감자용) 5. 피쉬 오일(2그램) 스테이크는 목초 사육, 시금치와 고추는 유기농으로 준비하면 최고의 식사가 됩니다. ``` ## 핵심 요약[[key-takeaways]] 나만의 문서 분석 집사를 만들고 싶다면 다음을 고려하세요: 1. **문서 관련 작업별로 명확한 도구 정의** 2. **도구 호출 간 맥락 유지를 위한 견고한 상태 추적기** 3. **도구 실패 시 오류 처리 고려** 4. **이전 상호작용 맥락 유지(add_messages 연산자 활용)** 이 원칙을 따르면 Wayne 저택에 어울리는 문서 분석 서비스를 제공할 수 있습니다. *이 설명이 도움이 되었길 바랍니다. 이제 주인님의 망토를 다림질하러 가보겠습니다.* ================================================ FILE: units/ko/unit2/langgraph/first_graph.mdx ================================================ # 나만의 첫 LangGraph 만들기[[building-your-first-langgraph]] 이제 LangGraph의 구성 요소를 이해했으니, 실제로 적용해보며 첫 번째 기능적 그래프를 만들어봅시다. 여기서는 알프레드의 이메일 처리 시스템을 구현할 것입니다. 알프레드는 다음과 같은 작업을 수행해야 합니다: 1. 들어오는 이메일 읽기 2. 스팸 또는 정상 메일로 분류하기 3. 정상 메일에 대한 임시 답장 작성하기 4. 정상 메일일 경우 Mr. Wayne에게 정보 전달(출력만) 이 예제는 LLM 기반 의사결정을 포함하는 LangGraph 워크플로우를 어떻게 구조화할 수 있는지를 보여줍니다. (여기서는 별도의 툴이 사용되지 않으므로 Agent라고 부르진 않지만, LangGraph 프레임워크 학습에 초점을 둡니다.) 이 노트북을 따라가며 Google Colab에서 코드를 실행해볼 수 있습니다. ## 우리가 만들 워크플로우[[our-workflow]] 아래와 같은 워크플로우를 구현합니다: First LangGraph ## 환경 설정[[setting-up-our-environment]] 먼저 필요한 패키지를 설치합니다: ```python %pip install langgraph langchain_openai ``` 필요한 모듈을 임포트합니다: ```python import os from typing import TypedDict, List, Dict, Any, Optional from langgraph.graph import StateGraph, START, END from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage ``` ## 1단계: 상태(State) 정의하기[[step-1-define-our-state]] 이메일 처리 워크플로우에서 알프레드가 추적해야 할 정보를 정의합니다: ```python class EmailState(TypedDict): # 처리 중인 이메일 email: Dict[str, Any] # 제목, 발신자, 본문 등 포함 # 이메일 분류(문의, 불만 등) email_category: Optional[str] # 스팸으로 분류된 이유 spam_reason: Optional[str] # 분석 및 결정 is_spam: Optional[bool] # 답장 생성 email_draft: Optional[str] # 처리 메타데이터 messages: List[Dict[str, Any]] # LLM과의 대화 추적 ``` > 💡 **팁:** 상태는 중요한 정보를 모두 담되, 불필요하게 비대해지지 않도록 하세요. ## 2단계: 노드 정의하기[[step-2-define-our-nodes]] 이제 각 처리 단계를 담당할 함수를 만듭니다: ```python # LLM 초기화 model = ChatOpenAI(temperature=0) def read_email(state: EmailState): """알프레드가 들어온 이메일을 읽고 기록합니다.""" email = state["email"] print(f"알프레드가 {email['sender']}로부터 온 메일(제목: {email['subject']})을 처리 중입니다.") return {} def classify_email(state: EmailState): """알프레드가 LLM을 사용해 이메일을 스팸/정상으로 분류합니다.""" email = state["email"] prompt = f""" 집사 알프레드로서, 이 이메일을 분석해 스팸인지 정상인지 판단하세요. 이메일: From: {email['sender']} Subject: {email['subject']} Body: {email['body']} 먼저 이 이메일이 스팸인지 판단하고, 스팸이라면 그 이유를 설명하세요. 정상 메일이라면 (문의, 불만, 감사, 요청 등) 카테고리도 분류하세요. """ messages = [HumanMessage(content=prompt)] response = model.invoke(messages) response_text = response.content.lower() is_spam = "spam" in response_text and "not spam" not in response_text spam_reason = None if is_spam and "reason:" in response_text: spam_reason = response_text.split("reason:")[1].strip() email_category = None if not is_spam: categories = ["inquiry", "complaint", "thank you", "request", "information"] for category in categories: if category in response_text: email_category = category break new_messages = state.get("messages", []) + [ {"role": "user", "content": prompt}, {"role": "assistant", "content": response.content} ] return { "is_spam": is_spam, "spam_reason": spam_reason, "email_category": email_category, "messages": new_messages } def handle_spam(state: EmailState): """알프레드가 스팸 메일을 처리합니다.""" print(f"알프레드는 이 메일을 스팸으로 분류했습니다. 이유: {state['spam_reason']}") print("이 메일은 스팸 폴더로 이동되었습니다.") return {} def draft_response(state: EmailState): """알프레드가 정상 메일에 임시 답장을 작성합니다.""" email = state["email"] category = state["email_category"] or "일반" prompt = f""" 집사 알프레드로서, 이 이메일에 정중한 임시 답장을 작성하세요. 이메일: From: {email['sender']} Subject: {email['subject']} Body: {email['body']} 이 이메일의 카테고리: {category} Mr. Hugg가 검토 후 개인화할 수 있도록 간단하고 전문적인 답장을 작성하세요. """ messages = [HumanMessage(content=prompt)] response = model.invoke(messages) new_messages = state.get("messages", []) + [ {"role": "user", "content": prompt}, {"role": "assistant", "content": response.content} ] return { "email_draft": response.content, "messages": new_messages } def notify_mr_hugg(state: EmailState): """알프레드가 Mr. Hugg에게 메일과 임시 답장을 전달합니다.""" email = state["email"] print("\n" + "="*50) print(f"주인님, {email['sender']}로부터 메일이 도착했습니다.") print(f"제목: {email['subject']}") print(f"카테고리: {state['email_category']}") print("\n검토하실 임시 답장을 준비했습니다:") print("-"*50) print(state["email_draft"]) print("="*50 + "\n") return {} ``` ## 3단계: 분기 로직 정의하기[[step-3-define-our-routing-logic]] 분류 후 어떤 경로로 갈지 결정하는 함수를 만듭니다: ```python def route_email(state: EmailState) -> str: """스팸 분류 결과에 따라 다음 단계를 결정합니다.""" if state["is_spam"]: return "spam" else: return "legitimate" ``` > 💡 **참고:** 이 라우팅 함수는 LangGraph가 분류 노드 이후 어떤 엣지를 따라갈지 결정할 때 호출됩니다. 반환값은 조건부 엣지 매핑의 키와 일치해야 합니다. ## 4단계: StateGraph 생성 및 엣지 정의[[step-4-create-the-stategraph-and-define-edges]] 이제 모든 것을 연결합니다: ```python # 그래프 생성 email_graph = StateGraph(EmailState) # 노드 추가 email_graph.add_node("read_email", read_email) email_graph.add_node("classify_email", classify_email) email_graph.add_node("handle_spam", handle_spam) email_graph.add_node("draft_response", draft_response) email_graph.add_node("notify_mr_hugg", notify_mr_hugg) # 엣지 시작 email_graph.add_edge(START, "read_email") # 흐름 정의 email_graph.add_edge("read_email", "classify_email") # 분기 추가 email_graph.add_conditional_edges( "classify_email", route_email, { "spam": "handle_spam", "legitimate": "draft_response" } ) # 마지막 엣지 email_graph.add_edge("handle_spam", END) email_graph.add_edge("draft_response", "notify_mr_hugg") email_graph.add_edge("notify_mr_hugg", END) # 그래프 컴파일 compiled_graph = email_graph.compile() ``` LangGraph에서 제공하는 특수한 `END` 노드를 사용합니다. 이는 워크플로우가 완료되는 지점을 나타냅니다. ## 5단계: 어플리케이션 실행하기[[step-5-run-the-application]] 정상 메일과 스팸 메일로 그래프를 테스트해봅니다: ```python # 정상 메일 예시 legitimate_email = { "sender": "john.smith@example.com", "subject": "서비스 문의", "body": "안녕하세요 Mr. Hugg, 동료의 추천으로 연락드립니다. 귀하의 컨설팅 서비스에 대해 더 알고 싶습니다. 다음 주에 통화 가능할까요? 감사합니다, John Smith" } # 스팸 메일 예시 spam_email = { "sender": "winner@lottery-intl.com", "subject": "당신은 $5,000,000에 당첨되었습니다!!!", "body": "축하합니다! 국제 복권에 당첨되셨습니다! 상금을 받으시려면 은행 정보와 수수료 $100을 보내주세요." } # 정상 메일 처리 print("\n정상 메일 처리 중...") legitimate_result = compiled_graph.invoke({ "email": legitimate_email, "is_spam": None, "spam_reason": None, "email_category": None, "email_draft": None, "messages": [] }) # 스팸 메일 처리 print("\n스팸 메일 처리 중...") spam_result = compiled_graph.invoke({ "email": spam_email, "is_spam": None, "spam_reason": None, "email_category": None, "email_draft": None, "messages": [] }) ``` ## 6단계: Langfuse로 메일 분류 에이전트 관찰하기 📡[[step-6-inspecting-our-mail-sorting-agent-with-langfuse]] 알프레드는 메일 분류 에이전트를 다듬으면서 디버깅에 지쳐갑니다. 에이전트는 본질적으로 예측 불가능하고 추적이 어렵기 때문입니다. 하지만 궁극의 스팸 감지 에이전트를 만들어 프로덕션에 배포하려면, 향후 모니터링과 분석을 위한 강력한 추적 기능이 필요합니다. 이를 위해 알프레드는 [Langfuse](https://langfuse.com/)와 같은 관찰 도구를 사용할 수 있습니다. 먼저 Langfuse를 설치합니다: ```python %pip install -q langfuse ``` LangChain도 설치합니다(Langfuse 사용 시 필요): ```python %pip install langchain ``` Langfuse API 키와 호스트 주소를 환경 변수로 추가합니다. [Langfuse Cloud](https://cloud.langfuse.com) 가입 또는 [셀프 호스팅](https://langfuse.com/self-hosting)으로 키를 발급받을 수 있습니다. ```python import os # 프로젝트 설정 페이지에서 키를 확인하세요: https://cloud.langfuse.com os.environ["LANGFUSE_PUBLIC_KEY"] = "pk-lf-..." os.environ["LANGFUSE_SECRET_KEY"] = "sk-lf-..." os.environ["LANGFUSE_HOST"] = "https://cloud.langfuse.com" # 🇪🇺 EU 리전 # os.environ["LANGFUSE_HOST"] = "https://us.cloud.langfuse.com" # 🇺🇸 US 리전 ``` [Langfuse `callback_handler`](https://langfuse.com/docs/integrations/langchain/tracing#add-langfuse-to-your-langchain-application)를 설정하고, 그래프 호출 시 `config={"callbacks": [langfuse_handler]}`로 인스트루먼트합니다. ```python from langfuse.langchain import CallbackHandler # LangGraph/Langchain용 Langfuse CallbackHandler 초기화(추적용) langfuse_handler = CallbackHandler() # 정상 메일 처리 legitimate_result = compiled_graph.invoke( input={"email": legitimate_email, "is_spam": None, "spam_reason": None, "email_category": None, "draft_response": None, "messages": []}, config={"callbacks": [langfuse_handler]} ) ``` 이제 알프레드는 LangGraph의 실행 내역을 Langfuse에 기록하여 에이전트의 동작을 완전히 파악할 수 있습니다. 이로써 이전 실행을 다시 살펴보고 메일 분류 에이전트를 더욱 개선할 수 있습니다. ![Langfuse 예시 트레이스](https://langfuse.com/images/cookbook/huggingface-agent-course/langgraph-trace-legit.png) _[정상 메일 트레이스 공개 링크](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/f5d6d72e-20af-4357-b232-af44c3728a7b?timestamp=2025-03-17T10%3A13%3A28.413Z&observation=6997ba69-043f-4f77-9445-700a033afba1)_ ## 그래프 시각화[[visualizing-our-graph]] LangGraph는 워크플로우 구조를 시각화하여 이해와 디버깅을 돕습니다: ```python compiled_graph.get_graph().draw_mermaid_png() ``` Mail LangGraph 이렇게 하면 노드 간 연결과 조건부 경로를 한눈에 볼 수 있습니다. ## 우리가 만든 것[[what-weve-built]] 우리는 다음과 같은 이메일 처리 워크플로우를 완성했습니다: 1. 들어온 이메일을 받음 2. LLM으로 스팸/정상 분류 3. 스팸은 폐기 4. 정상 메일은 답장 작성 후 Mr. Hugg에게 전달 이처럼 LangGraph를 활용하면 LLM 기반의 복잡한 워크플로우도 명확하고 구조적으로 오케스트레이션할 수 있습니다. ## 핵심 요약[[key-takeaways]] - **상태 관리**: 이메일 처리의 모든 측면을 추적할 수 있도록 상태를 정의 - **노드 구현**: LLM과 상호작용하는 기능적 노드 구현 - **조건부 분기**: 이메일 분류 결과에 따라 분기 로직 구현 - **종료 상태**: END 노드로 워크플로우 종료 지점 표시 ## 다음 단계[[whats-next]] 다음 섹션에서는 LangGraph의 고급 기능(사람과의 상호작용, 다중 조건 분기 등)을 다룹니다. ================================================ FILE: units/ko/unit2/langgraph/introduction.mdx ================================================ # `LangGraph` 소개[[introduction-to-langgraph]] Unit 2.3 Thumbnail 다음 단계에 오신 것을 환영합니다! 이 단원에서는 복잡한 LLM 워크플로우를 구조화하고 조정, 관리할 수 있도록 설계된 [`LangGraph`](https://github.com/langchain-ai/langgraph) 프레임워크를 사용하여 **어플리케이션을 구축하는 방법**을 배우게 됩니다. `LangGraph`는 에이전트의 흐름을 **직접 제어**할 수 있는 도구를 제공하여 **프로덕션 수준**의 어플리케이션을 만들 수 있게 해주는 프레임워크입니다. ## 모듈 개요[[module-overview]] 이 단원에서 함께 살펴볼 주제는 다음과 같습니다 ### 1️⃣ LangGraph란 무엇이며, 언제 사용해야 할까?[[1-what-is-langgraph-and-when-to-use-it]] ### 2️⃣ LangGraph의 구성 요소[[2-building-blocks-of-langgraph]] ### 3️⃣ 내 메일을 대신 분류해주는 집사[[3-alfred-the-mail-sorting-butler]] ### 4️⃣ 알프레드, 문서 분석 에이전트[[4-alfred-the-document-analyst-agent]] ### 5️⃣ 퀴즈 [[5-quiz]] 이 섹션의 예제들은 강력한 LLM/VLM 모델이 필요합니다. 이 코스에서는 langGraph와 가장 호환성이 좋은 GPT-4o API를 사용해 실행하였습니다. 이 단원이 끝나면, 여러분은 견고하고 체계적인, 프로덕션에 바로 투입 가능한 어플리케이션을 만들 수 있게 됩니다! 이 섹션은 LangGraph의 입문 과정이니, 더 심화된 주제는 무료 LangChain 아카데미 강의 [LangGraph 소개](https://academy.langchain.com/courses/intro-to-langgraph)에서 확인할 수 있습니다. 그럼 시작해볼까요? ## 참고 자료[[resources]] - [LangGraph Agents](https://langchain-ai.github.io/langgraph/) - LangGraph 에이전트 예제 - [LangChain academy](https://academy.langchain.com/courses/intro-to-langgraph) - LangChain에서 제공하는 LangGraph 전체 강의 ================================================ FILE: units/ko/unit2/langgraph/quiz1.mdx ================================================ # LangGraph 이해도 테스트 [[test-your-understanding-of-langgraph]] `LangGraph`에 대한 이해도를 간단한 퀴즈로 확인해보세요! 지금까지 배운 핵심 개념을 복습하는 데 도움이 됩니다. 이 퀴즈는 선택 사항이며 채점되지 않습니다. ### Q1: LangGraph의 주요 목적은 무엇인가요? [[q1-what-is-the-primary-purpose-of-langgraph]] LangGraph가 무엇을 위해 설계되었는지 가장 잘 설명하는 문장은? --- ### Q2: "제어 vs 자유" 관점에서 LangGraph는 어디에 속하나요? [[q2-in-the-context-of-the-control-vs-freedom-trade-off-where-does-langgraph-stand]] 다음 중 LangGraph의 에이전트 설계 접근 방식을 가장 잘 설명한 문장은? --- ### Q3: LangGraph에서 상태(State)의 역할은 무엇인가요? [[q3-what-role-does-state-play-in-langgraph]] 다음 중 LangGraph에서 상태(State)에 대한 설명으로 가장 적절한 것은? ### Q4: LangGraph에서 조건부 엣지(Conditional Edge)란 무엇인가요? [[q4-what-is-a-conditional-edge-in-langgraph]] 조건부 엣지에 대한 설명으로 가장 적절한 것은? --- ### Q5: LangGraph는 LLM의 환각(hallucination) 문제를 어떻게 해결하는 데 도움이 되나요? [[q5-how-does-langgraph-help-address-the-hallucination-problem-in-llms]] 환각에 대한 설명으로 가장 적절한 것은? 축하합니다! 🎉 틀린 문제가 있다면, 앞에서 다룬 내용들을 다시 검토해보세요. 이제 LangGraph의 더 심화 기능을 알아보고, 더 복잡한 에이전트 워크플로우를 구축하는 방법을 배워봅시다. ================================================ FILE: units/ko/unit2/langgraph/when_to_use_langgraph.mdx ================================================ # `LangGraph`란 무엇인가요? [[what-is-langgraph]] `LangGraph`는 [LangChain](https://www.langchain.com/)에서 개발한 프레임워크로, **LLM을 통합한 어플리케이션의 제어 흐름을 관리**하기 위해 만들어졌습니다. ## `LangGraph`는 `LangChain`와 어떻게 다른가요? [[is-langgraph-different-from-langchain]] LangChain은 모델 및 기타 구성 요소와 상호작용하기 위한 표준 인터페이스를 제공하며, 검색, LLM 호출, 도구 호출에 유용합니다. LangChain의 클래스들은 LangGraph에서 사용될 수 있지만, 반드시 사용해야 하는 것은 아닙니다. 두 패키지는 서로 다른 패키지이며, 각각 독립적으로 사용할 수 있지만, 실제로 온라인에서 찾을 수 있는 대부분의 예제에서는 두 패키지를 함께 사용하는 경우가 많습니다. ## 언제 `LangGraph`를 사용해야 할까요? [[when-should-i-use-langgraph-]] ### 제어 vs 자유 [[control-vs-freedom]] AI 어플리케이션을 설계할 때, **제어**와 **자유** 사이의 트레이드오프를 고려해야합니다: - **자유**는 LLM이 더 많은 창의성을 발휘하고 예상치 못한 문제를 해결할 수 있도록 합니다. - **제어**는 예측 가능한 동작을 보장하고 안전 장치를 유지할 수 있습니다. *smolagents*의 코드 에이전트는 매우 자유롭습니다. 하나의 액션 단계에서 여러 도구를 호출하거나, 자체적으로 도구를 만들기도 합니다. 하지만 이런 동작은 JSON 기반 에이전트보다 예측하기 어렵고 제어하기 어렵게 만듭니다! `LangGraph`는 스펙트럼의 반대편에 있으며, 에이전트 실행에 **"제어"**가 필요할 때 빛납니다. LangGraph는 특히 **어플리케이션에 대한 제어**가 필요할 때 가치가 있습니다. 예측 가능한 프로세스를 따르면서도 LLM의 힘을 활용할 수 있도록 돕는 도구를 제공합니다. 간단히 말하면, 어플리케이션이 특정 방식으로 구성된 일련의 단계를 거쳐야하고, 각 분기점에서 의사결정이 내려져야 한다면, **LangGraph가 그 필요한 구조를 제공해줍니다**. 예를 들어, 문서에 대한 질문에 답할 수 있는 LLM 어시스턴트를 구축하고 싶다고 가정해봅시다. LLM이 텍스트를 가장 잘 이해하기 때문에, 질문에 답하기 전에 복잡한 형태들(차트, 표)을 텍스트로 변환해야 합니다. 하지만 그 선택은 문서의 유형에 따라 달라집니다! 이러한 분기 흐름은 아래와 같이 표현할 수 있습니다: Control flow > 💡 **팁:** 왼쪽 부분은 도구 호출이 없기 때문에 에이전트가 아닙니다. 그러나 오른쪽 부분은 엑셀 파일을 쿼리하기 위해 코드를 작성해야 하므로 에이전트가 필요합니다.(예: pandas로 변환하고 조작). 이 분기는 결정적이지만, LLM 출력에 따라 조건이 정해지는 비결정적 분기도 설계할 수 있습니다. LangGraph가 유용한 경우: - **명시적인 흐름 제어가 필요한 다단계 논리적 추론 프로세스** - **단계 간 상태 지속이 필요한 어플리케이션** - **결정론적 로직과 AI 기능을 결합하는 시스템** - **사람의 개입이 필요한 워크플로우** - **여러 구성 요소가 함께 작동하는 복잡한 에이전트 아키텍처** 요약하자면, 최대한 **사람이 직접** 각 단계의 출력에 따라 실행할 다음 단계를 설계해야 하는 경우, LangGraph가 가장 적절합니다! `LangGraph`는 제 생각에 시장에서 가장 프로덕션 준비가 잘 된 에이전트 프레임워크입니다. ## LangGraph는 어떻게 작동하나요? [[how-does-langgraph-work]] `LangGraph`는 어플리케이션의 흐름을 정의하기 위해 방향성 그래프 구조를 사용합니다: - **노드(Node)**는 각 처리 단계를 나타냅니다(LLM 호출, 도구 사용, 의사결정 등). - **엣지(Edge)**는 단계 간 가능한 전환을 정의합니다. - **상태(State)**는 사용자가 정의하고 유지하며 실행 중 노드 간에 전달됩니다. 다음에 어떤 노드를 실행할지 결정할 때, 현재 상태가 기준입니다. 이러한 기본 구성 요소들은 다음 장에서 더 자세히 살펴보겠습니다! ## 일반 파이썬과 어떻게 다른가요? 왜 LangGraph가 필요한가요? [[how-is-it-different-from-regular-python-why-do-i-need-langgraph]] "그냥 일반 파이썬 문법으로 if-else 문 쓰면 되지 않나요?"라고 궁금해할 수 있습니다. 기술적으로는 가능하지만, LangGraph는 복잡한 시스템 구축을 위해 일반 파이썬보다 **여러 가지 장점**을 제공합니다. LangGraph 없이도 동일한 어플리케이션을 구축할 수 있지만, LangGraph는 더 쉽게 개발할 수 있는 도구와 추상화를 제공합니다. 예: 상태 관리, 시각화, 로깅(트레이스), 내장형 사용자 개입 처리 기능 등. ================================================ FILE: units/ko/unit2/llama-index/README.md ================================================ # 목차 이 LlamaIndex 프레임 개요는 강의 2단원의 일부입니다. hf.co/learn에서 LlamaIndex에 대한 2단원에 접근할 수 있습니다 👉 여기 | 제목 | 설명 | | --- | --- | | [소개](introduction.mdx) | LlamaIndex 소개 | | [LlamaHub](llama-hub.mdx) | LlamaHub: 통합, 에이전트, 툴의 레지스트리 | | [구성 요소](components.mdx) | 구성 요소: 워크플로우의 빌딩 블록 | | [툴](tools.mdx) | 툴: LlamaIndex에서 툴을 구축하는 방법 | | [퀴즈 1](quiz1.mdx) | 퀴즈 1 | | [에이전트](agents.mdx) | 에이전트: LlamaIndex에서 에이전트를 구축하는 방법 | | [워크플로우](workflows.mdx) | 워크플로우: 순서대로 실행되는 구성 요소로 만들어진 단계, 이벤트의 시퀀스 | | [퀴즈 2](quiz2.mdx) | 퀴즈 2 | | [결론](conclusion.mdx) | 결론 | ================================================ FILE: units/ko/unit2/llama-index/agents.mdx ================================================ # LlamaIndex에서 에이전트 사용하기 이전에 나왔던 도움이 되는 집사 에이전트 알프레드를 기억하시나요? 이제 그가 업그레이드를 받을 차례입니다! 이제 LlamaIndex에서 사용할 수 있는 툴들을 이해했으니, 알프레드에게 더 나은 서비스를 제공할 수 있는 새로운 기능들을 부여할 수 있습니다. 하지만 계속하기 전에, 알프레드 같은 에이전트가 어떻게 작동하는지 다시 한번 상기해봅시다. 1단원에서 우리는 다음을 배웠습니다: > 에이전트는 사용자가 정의한 목표를 달성하기 위해 AI 모델을 활용하여 환경과 상호작용하는 시스템입니다. 작업을 수행하기 위해 추론, 계획, 액션 실행(종종 외부 툴을 통해)을 결합합니다. LlamaIndex는 **세 가지 주요 유형의 추론 에이전트**를 지원합니다: ![에이전트](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/agents.png) 1. `Function Calling Agents` - 특정 함수를 호출할 수 있는 AI 모델과 함께 작동합니다. 2. `ReAct Agents` - 채팅이나 텍스트 엔드포인트를 수행하는 모든 AI와 함께 작동할 수 있으며, 복잡한 추론 작업을 처리합니다. 3. `Advanced Custom Agents` - 더 복잡한 작업과 워크플로우를 처리하기 위해 더 복잡한 방법을 사용합니다. 고급 에이전트에 대한 더 많은 정보는 BaseWorkflowAgent에서 찾을 수 있습니다. ## 에이전트 초기화 이 노트북을 따라가며 Google Colab에서 코드를 실행해볼 수 있습니다. 에이전트를 만들기 위해, 먼저 **기능을 정의하는 함수/툴 세트**를 제공합니다. 몇 가지 기본 툴로 에이전트를 만드는 방법을 살펴보겠습니다. 현재로서는 에이전트가 자동으로 함수 호출 API(사용 가능한 경우) 또는 표준 ReAct 에이전트 루프를 사용합니다. 툴/함수 API를 지원하는 LLM들은 비교적 최신이지만, 특정 프롬프팅을 피하고 제공된 스키마를 기반으로 LLM이 툴 호출을 생성할 수 있게 하여 툴을 호출하는 강력한 방법을 제공합니다. ReAct 에이전트는 또한 복잡한 추론 작업에 능숙하며, 채팅이나 텍스트 완성 기능이 있는 모든 LLM과 함께 작동할 수 있습니다. 더 상세하며, 수행하는 특정 액션의 추론 과정을 보여줍니다. ```python from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI from llama_index.core.agent.workflow import AgentWorkflow from llama_index.core.tools import FunctionTool # 샘플 툴 정의 -- 타입 어노테이션, 함수 이름, 독스트링이 모두 파싱된 스키마에 포함됩니다! def multiply(a: int, b: int) -> int: """두 정수를 곱하고 결과 정수를 반환합니다""" return a * b # llm 초기화 llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") # 에이전트 초기화 agent = AgentWorkflow.from_tools_or_functions( [FunctionTool.from_defaults(multiply)], llm=llm ) ``` **에이전트는 기본적으로 상태가 없으며**, 과거 상호작용을 기억하는 것은 `Context` 객체를 사용하여 선택사항입니다. 이는 여러 메시지에 걸쳐 맥락을 유지하는 챗봇이나 시간이 지남에 따라 진행 상황을 추적해야 하는 작업 관리자처럼 이전 상호작용을 기억해야 하는 에이전트를 사용하고 싶을 때 유용할 수 있습니다. ```python # 상태 없음 response = await agent.run("2 곱하기 2는 무엇인가요?") # 상태 기억 from llama_index.core.workflow import Context ctx = Context(agent) response = await agent.run("내 이름은 Bob입니다.", ctx=ctx) response = await agent.run("내 이름이 뭐였지?", ctx=ctx) ``` `LlamaIndex`의 에이전트들이 Python의 `await` 연산자를 사용하기 때문에 비동기라는 것을 알 수 있습니다. Python의 비동기 코드가 처음이거나 복습이 필요하다면, [훌륭한 비동기 가이드](https://docs.llamaindex.ai/en/stable/getting_started/async_python/)가 있습니다. 이제 기본을 마스터했으니, 에이전트에서 더 복잡한 툴을 사용하는 방법을 살펴보겠습니다. ## QueryEngineTools로 RAG 에이전트 만들기 **에이전트 RAG는 에이전트를 사용하여 데이터에 대한 질문에 답하는 강력한 방법입니다.** 알프레드가 질문에 답하는 데 도움이 되도록 다양한 툴을 전달할 수 있습니다. 하지만 문서 위에서 자동으로 질문에 답하는 대신, 알프레드는 질문에 답하기 위해 다른 툴이나 흐름을 사용할지 결정할 수 있습니다. ![에이전트 RAG](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/agentic-rag.png) 에이전트를 위해 **`QueryEngine`을 툴로 래핑**하는 것은 쉽습니다. 이렇게 할 때, **이름과 설명을 정의**해야 합니다. LLM은 이 정보를 사용하여 툴을 올바르게 사용합니다. [구성 요소 섹션](components)에서 만든 `QueryEngine`을 사용하여 `QueryEngineTool`을 로드하는 방법을 살펴보겠습니다. ```python from llama_index.core.tools import QueryEngineTool query_engine = index.as_query_engine(llm=llm, similarity_top_k=3) # LlamaIndex의 구성 요소 섹션에서 보여진 대로 query_engine_tool = QueryEngineTool.from_defaults( query_engine=query_engine, name="name", description="a specific description", return_direct=False, ) query_engine_agent = AgentWorkflow.from_tools_or_functions( [query_engine_tool], llm=llm, system_prompt="You are a helpful assistant that has access to a database containing persona descriptions. " ) ``` ## 다중 에이전트 시스템 만들기 `AgentWorkflow` 클래스는 다중 에이전트 시스템도 직접 지원합니다. 각 에이전트에 이름과 설명을 부여함으로써, 시스템은 단일 활성 발화자를 유지하며, 각 에이전트는 다른 에이전트에게 작업을 넘길 수 있는 능력을 가집니다. 각 에이전트의 범위를 좁힘으로써, 사용자 메시지에 응답할 때 일반적인 정확도를 높이는 데 도움이 될 수 있습니다. **LlamaIndex의 에이전트들은 더 복잡하고 사용자 정의 시나리오를 위해 다른 에이전트의 툴로도 직접 사용될 수 있습니다.** ```python from llama_index.core.agent.workflow import ( AgentWorkflow, FunctionAgent, ReActAgent, ) # 몇 가지 툴 정의 def add(a: int, b: int) -> int: """두 숫자를 더합니다.""" return a + b def subtract(a: int, b: int) -> int: """두 숫자를 뺍니다.""" return a - b # 에이전트 설정 생성 # 참고: 여기서 FunctionAgent 또는 ReActAgent를 사용할 수 있습니다. # FunctionAgent는 함수 호출 API가 있는 LLM용입니다. # ReActAgent는 모든 LLM용입니다. calculator_agent = ReActAgent( name="calculator", description="기본 산술 연산을 수행합니다", system_prompt="당신은 계산기 어시스턴트입니다. 모든 수학 연산에 툴을 사용하세요.", tools=[add, subtract], llm=llm, ) query_agent = ReActAgent( name="info_lookup", description="XYZ에 대한 정보를 찾습니다", system_prompt="XYZ에 대한 정보를 답하기 위해 RAG 시스템을 쿼리하는 툴을 사용하세요", tools=[query_engine_tool], llm=llm ) # 워크플로우 생성 및 실행 agent = AgentWorkflow( agents=[calculator_agent, query_agent], root_agent="calculator" ) # 시스템 실행 response = await agent.run(user_msg="5와 3을 더할 수 있나요?") ``` 아직 충분히 배우지 못했나요? AgentWorkflow 기본 소개 또는 에이전트 학습 가이드에서 LlamaIndex의 에이전트와 툴에 대해 더 많은 것을 발견할 수 있으며, 스트리밍, 맥락 직렬화, 사람 개입에 대해 더 읽을 수 있습니다! 이제 LlamaIndex에서 에이전트와 툴의 기본을 이해했으니, LlamaIndex를 사용하여 **구성 가능하고 관리 가능한 워크플로우를 만드는** 방법을 살펴보겠습니다! ================================================ FILE: units/ko/unit2/llama-index/components.mdx ================================================ # LlamaIndex의 구성 요소란 무엇인가요? 1단원에서 나왔던 도움이 되는 집사 에이전트 알프레드를 기억하시나요? 효과적으로 우리를 도우려면, 알프레드는 우리의 요청을 이해하고 **작업을 완료하는 데 도움이 되는 관련 정보를 준비하고, 찾고, 사용**할 수 있어야 합니다. 이것이 LlamaIndex의 구성 요소가 들어오는 곳입니다. LlamaIndex에는 많은 구성 요소가 있지만, **우리는 특별히 `QueryEngine` 구성 요소에 집중할 것입니다.** 왜냐고요? 에이전트의 검색 증강 생성(RAG) 툴로 사용할 수 있기 때문입니다. 그럼 RAG란 무엇일까요? LLM은 일반적인 지식을 배우기 위해 엄청난 양의 데이터로 훈련됩니다. 하지만 관련 있고 최신 데이터로 훈련되지 않았을 수 있습니다. RAG는 데이터에서 관련 정보를 찾고 검색하여 LLM에게 제공함으로써 이 문제를 해결합니다. ![RAG](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/rag.png) 이제 알프레드가 어떻게 작동하는지 생각해보세요: 1. 알프레드에게 저녁 파티 계획을 도와달라고 요청합니다 2. 알프레드는 캘린더, 식이 선호도, 과거 성공한 메뉴를 확인해야 합니다 3. `QueryEngine`이 알프레드가 이 정보를 찾고 저녁 파티 계획에 사용하도록 도와줍니다 이것이 `QueryEngine`을 LlamaIndex에서 **에이전트 RAG 워크플로우를 구축하기 위한 핵심 구성 요소**로 만듭니다. 알프레드가 도움이 되기 위해 가정 정보를 검색해야 하는 것처럼, 모든 에이전트는 관련 데이터를 찾고 이해할 수 있는 방법이 필요합니다. `QueryEngine`은 정확히 이 기능을 제공합니다. 이제 구성 요소에 대해 조금 더 깊이 들어가서 **구성 요소를 결합하여 RAG 파이프라인을 만드는** 방법을 살펴보겠습니다. ## 구성 요소를 사용하여 RAG 파이프라인 만들기 이 노트북을 따라가며 Google Colab에서 코드를 실행해볼 수 있습니다. RAG 내에는 5가지 주요 단계가 있으며, 이는 구축하는 대부분의 더 큰 어플리케이션의 일부가 됩니다: 1. **로딩**: 데이터가 있는 곳(텍스트 파일, PDF, 다른 웹사이트, 데이터베이스, API)에서 워크플로우로 데이터를 가져오는 것을 의미합니다. LlamaHub는 선택할 수 있는 수백 개의 통합을 제공합니다. 2. **인덱싱**: 데이터를 쿼리할 수 있는 데이터 구조를 만드는 것을 의미합니다. LLM의 경우, 이는 거의 항상 벡터 임베딩을 만드는 것을 의미합니다. 이는 데이터 의미의 수치적 표현입니다. 인덱싱은 속성을 기반으로 맥락적으로 관련된 데이터를 정확하게 찾기 쉽게 만드는 수많은 다른 메타데이터 전략을 의미할 수도 있습니다. 3. **저장**: 데이터가 인덱싱되면 다시 인덱싱할 필요가 없도록 인덱스와 다른 메타데이터를 저장하고 싶을 것입니다. 4. **쿼리**: 주어진 인덱싱 전략에 대해 하위 쿼리, 다단계 쿼리, 하이브리드 전략을 포함하여 LLM과 LlamaIndex 데이터 구조를 사용하여 쿼리할 수 있는 많은 방법이 있습니다. 5. **평가**: 모든 흐름에서 중요한 단계는 다른 전략에 비해 얼마나 효과적인지, 또는 변경사항을 만들 때 확인하는 것입니다. 평가는 쿼리에 대한 응답이 얼마나 정확하고, 신뢰할 수 있고, 빠른지에 대한 객관적인 측정을 제공합니다. 다음으로, 구성 요소를 사용하여 이러한 단계들을 재현하는 방법을 살펴보겠습니다. ### 문서 로딩 및 임베딩 앞서 언급했듯이, LlamaIndex는 자체 데이터 위에서 작동할 수 있지만, **데이터에 접근하기 전에 로드해야 합니다.** LlamaIndex에 데이터를 로드하는 세 가지 주요 방법이 있습니다: 1. `SimpleDirectoryReader`: 로컬 디렉토리에서 다양한 파일 유형을 위한 내장 로더입니다. 2. `LlamaParse`: PDF 파싱을 위한 LlamaIndex의 공식 툴인 LlamaParse로, 관리형 API로 사용 가능합니다. 3. `LlamaHub`: 모든 소스에서 데이터를 수집하기 위한 수백 개의 데이터 로딩 라이브러리 레지스트리입니다. 더 복잡한 데이터 소스를 위해 LlamaHub 로더와 LlamaParse 파서에 익숙해지세요. **데이터를 로드하는 가장 간단한 방법은 `SimpleDirectoryReader`를 사용하는 것입니다.** 이 다재다능한 구성 요소는 폴더에서 다양한 파일 유형을 로드하고 LlamaIndex가 작업할 수 있는 `Document` 객체로 변환할 수 있습니다. `SimpleDirectoryReader`를 사용하여 폴더에서 데이터를 로드하는 방법을 살펴보겠습니다. ```python from llama_index.core import SimpleDirectoryReader reader = SimpleDirectoryReader(input_dir="path/to/directory") documents = reader.load_data() ``` 문서를 로드한 후, `Node` 객체라는 더 작은 조각들로 나누어야 합니다. `Node`는 AI가 작업하기 더 쉬운 원본 문서의 텍스트 청크일 뿐이며, 여전히 원본 `Document` 객체에 대한 참조를 가지고 있습니다. `IngestionPipeline`은 두 가지 주요 변환을 통해 이러한 노드를 만드는 데 도움이 됩니다. 1. `SentenceSplitter`는 자연스러운 문장 경계에서 문서를 분할하여 관리 가능한 청크로 나눕니다. 2. `HuggingFaceEmbedding`은 각 청크를 수치적 임베딩으로 변환합니다 - AI가 효율적으로 처리할 수 있는 방식으로 의미적 의미를 포착하는 벡터 표현입니다. 이 과정은 검색과 분석에 더 유용한 방식으로 문서를 구성하는 데 도움이 됩니다. ```python from llama_index.core import Document from llama_index.embeddings.huggingface import HuggingFaceEmbedding from llama_index.core.node_parser import SentenceSplitter from llama_index.core.ingestion import IngestionPipeline # 변환과 함께 파이프라인 생성 pipeline = IngestionPipeline( transformations=[ SentenceSplitter(chunk_overlap=0), HuggingFaceEmbedding(model_name="BAAI/bge-small-en-v1.5"), ] ) nodes = await pipeline.arun(documents=[Document.example()]) ``` ### 문서 저장 및 인덱싱 `Node` 객체를 만든 후, 검색 가능하게 만들기 위해 인덱싱해야 하지만, 그 전에 데이터를 저장할 곳이 필요합니다. 수집 파이프라인을 사용하고 있으므로, 파이프라인에 벡터 스토어를 직접 연결하여 채울 수 있습니다. 이 경우, 문서를 저장하기 위해 `Chroma`를 사용할 것입니다.
ChromaDB 설치 LlamaHub 섹션에서 소개된 대로, 다음 명령어로 ChromaDB 벡터 스토어를 설치할 수 있습니다: ```bash pip install llama-index-vector-stores-chroma ```
```python import chromadb from llama_index.vector_stores.chroma import ChromaVectorStore db = chromadb.PersistentClient(path="./alfred_chroma_db") chroma_collection = db.get_or_create_collection("alfred") vector_store = ChromaVectorStore(chroma_collection=chroma_collection) pipeline = IngestionPipeline( transformations=[ SentenceSplitter(chunk_size=25, chunk_overlap=0), HuggingFaceEmbedding(model_name="BAAI/bge-small-en-v1.5"), ], vector_store=vector_store, ) ``` 다양한 벡터 스토어에 대한 개요는 LlamaIndex 문서에서 찾을 수 있습니다. 이것이 벡터 임베딩이 들어오는 곳입니다 - 쿼리와 노드를 같은 벡터 공간에 임베딩함으로써 관련 매치를 찾을 수 있습니다. `VectorStoreIndex`는 일관성을 보장하기 위해 수집 중에 사용한 것과 같은 임베딩 모델을 사용하여 이를 처리합니다. 벡터 스토어와 임베딩에서 이 인덱스를 만드는 방법을 살펴보겠습니다: ```python from llama_index.core import VectorStoreIndex from llama_index.embeddings.huggingface import HuggingFaceEmbedding embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-small-en-v1.5") index = VectorStoreIndex.from_vector_store(vector_store, embed_model=embed_model) ``` 모든 정보는 `ChromaVectorStore` 객체와 전달된 디렉토리 경로 내에서 자동으로 지속됩니다. 훌륭합니다! 이제 인덱스를 쉽게 저장하고 로드할 수 있으니, 다양한 방법으로 쿼리하는 방법을 탐구해보겠습니다. ### 프롬프트와 LLM으로 VectorStoreIndex 쿼리하기 인덱스를 쿼리하기 전에, 쿼리 인터페이스로 변환해야 합니다. 가장 일반적인 변환 옵션은 다음과 같습니다: - `as_retriever`: 기본 문서 검색용으로, 유사도 점수가 있는 `NodeWithScore` 객체 리스트를 반환합니다 - `as_query_engine`: 단일 질문-답변 상호작용용으로, 작성된 응답을 반환합니다 - `as_chat_engine`: 여러 메시지에 걸쳐 메모리를 유지하는 대화형 상호작용용으로, 채팅 기록과 인덱싱된 맥락을 사용하여 작성된 응답을 반환합니다 에이전트와 같은 상호작용에 더 일반적이므로 쿼리 엔진에 집중하겠습니다. 응답에 사용할 LLM도 쿼리 엔진에 전달합니다. ```python from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") query_engine = index.as_query_engine( llm=llm, response_mode="tree_summarize", ) query_engine.query("인생의 의미는 무엇인가요?") # 인생의 의미는 42입니다 ``` ### 응답 처리 내부적으로, 쿼리 엔진은 질문에 답하기 위해 LLM만 사용하는 것이 아니라 응답을 처리하기 위한 전략으로 `ResponseSynthesizer`도 사용합니다. 다시 한번, 이것은 완전히 사용자 정의 가능하지만 즉시 잘 작동하는 세 가지 주요 전략이 있습니다: - `refine`: 검색된 각 텍스트 청크를 순차적으로 거쳐 답변을 생성하고 개선합니다. 이는 Node/검색된 청크당 별도의 LLM 호출을 만듭니다. - `compact` (기본값): 개선과 유사하지만 미리 청크를 연결하여 더 적은 LLM 호출을 만듭니다. - `tree_summarize`: 검색된 각 텍스트 청크를 거쳐 답변의 트리 구조를 만들어 상세한 답변을 생성합니다. 저수준 구성 API로 쿼리 워크플로우를 세밀하게 제어하세요. 이 API는 쿼리 프로세스의 모든 단계를 사용자 정의하고 미세 조정하여 정확한 요구사항에 맞출 수 있게 해주며, 워크플로우와도 잘 맞습니다. 언어 모델이 항상 예측 가능한 방식으로 수행되지 않을 수 있으므로, 우리가 얻는 답변이 항상 정확하다고 확신할 수 없습니다. **답변의 품질을 평가**함으로써 이를 처리할 수 있습니다. ### 평가 및 관찰 가능성 LlamaIndex는 **응답 품질을 평가하기 위한 내장 평가 도구**를 제공합니다. 이러한 평가자는 LLM을 활용하여 다양한 차원에서 응답을 분석합니다. 사용 가능한 세 가지 주요 평가자를 살펴보겠습니다: - `FaithfulnessEvaluator`: 답변이 맥락에 의해 지원되는지 확인하여 답변의 신뢰성을 평가합니다. - `AnswerRelevancyEvaluator`: 답변이 질문과 관련이 있는지 확인하여 답변의 관련성을 평가합니다. - `CorrectnessEvaluator`: 답변이 정확한지 확인하여 답변의 정확성을 평가합니다. 에이전트 관찰 가능성과 평가에 대해 더 배우고 싶나요? 보너스 단원 2로 여정을 계속하세요. ```python from llama_index.core.evaluation import FaithfulnessEvaluator query_engine = # 이전 섹션에서 llm = # 이전 섹션에서 # 인덱스 쿼리 evaluator = FaithfulnessEvaluator(llm=llm) response = query_engine.query( "미국 혁명에서 뉴욕시에서 어떤 전투가 일어났나요?" ) eval_result = evaluator.evaluate_response(response=response) eval_result.passing ``` 직접적인 평가 없이도 **관찰 가능성을 통해 시스템이 어떻게 수행되고 있는지에 대한 통찰을 얻을 수 있습니다.** 이는 더 복잡한 워크플로우를 구축하고 각 구성 요소가 어떻게 수행되고 있는지 이해하고 싶을 때 특히 유용합니다.
LlamaTrace 설치 LlamaHub 섹션에서 소개된 대로, 다음 명령어로 Arize Phoenix의 LlamaTrace 콜백을 설치할 수 있습니다: ```bash pip install -U llama-index-callbacks-arize-phoenix ``` 또한 LlamaTrace API 키를 `PHOENIX_API_KEY` 환경 변수로 설정해야 합니다. 다음을 통해 얻을 수 있습니다: - [LlamaTrace](https://llamatrace.com/login)에서 계정 생성 - 계정 설정에서 API 키 생성 - 아래 코드에서 추적을 활성화하기 위해 API 키 사용
```python import llama_index import os PHOENIX_API_KEY = "" os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = f"api_key={PHOENIX_API_KEY}" llama_index.core.set_global_handler( "arize_phoenix", endpoint="https://llamatrace.com/v1/traces" ) ``` 구성 요소와 사용 방법에 대해 더 배우고 싶나요? 구성 요소 가이드 또는 RAG 가이드로 여정을 계속하세요. 구성 요소를 사용하여 `QueryEngine`을 만드는 방법을 보았습니다. 이제 **`QueryEngine`을 에이전트의 툴로 사용하는** 방법을 살펴보겠습니다! ================================================ FILE: units/ko/unit2/llama-index/conclusion.mdx ================================================ # 결론 2단원의 `llama-index` 모듈을 완료하신 것을 축하합니다! 🥳 방금 `llama-index`의 기본을 마스터하고 자신만의 에이전트 워크플로우를 구축하는 방법을 보셨습니다! 이제 `llama-index` 기술을 갖추셨으니, 관심 있는 작업을 해결할 검색 엔진을 만들기 시작할 수 있습니다. 이 단원의 다음 모듈에서는 **LangGraph로 에이전트를 구축하는 방법**을 배우게 됩니다. 마지막으로, **강의에 대한 여러분의 생각과 개선 방법**을 듣고 싶습니다. 피드백이 있으시면 👉 [이 양식을 작성해주세요](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ### 계속 배우고, 멋지게 유지하세요! 🤗 ================================================ FILE: units/ko/unit2/llama-index/introduction.mdx ================================================ # LlamaIndex 소개 [LlamaIndex](https://www.llamaindex.ai/) 툴킷을 사용하여 LLM 기반 에이전트를 구축하는 방법을 배우는 이 모듈에 오신 것을 환영합니다. LlamaIndex는 **인덱스와 워크플로우를 사용하여 데이터 위에서 LLM 기반 에이전트를 만드는 완전한 툴킷**입니다. 이 강의에서는 LlamaIndex에서 에이전트를 구축하는 데 도움이 되는 세 가지 주요 부분에 집중할 것입니다: **구성 요소**, **에이전트와 툴**, 그리고 **워크플로우**입니다. ![LlamaIndex](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/thumbnail.png) LlamaIndex의 이러한 핵심 부분들과 에이전트에 어떻게 도움이 되는지 살펴보겠습니다: - **구성 요소**: LlamaIndex에서 사용하는 기본 빌딩 블록입니다. 프롬프트, 모델, 데이터베이스 등이 포함됩니다. 구성 요소는 종종 LlamaIndex를 다른 툴과 라이브러리와 연결하는 데 도움이 됩니다. - **툴**: 검색, 계산, 외부 서비스 접근과 같은 특정 기능을 제공하는 구성 요소입니다. 에이전트가 작업을 수행할 수 있게 하는 빌딩 블록입니다. - **에이전트**: 툴을 사용하고 결정을 내릴 수 있는 자율 구성 요소입니다. 복잡한 목표를 달성하기 위해 툴 사용을 조정합니다. - **워크플로우**: 로직을 함께 처리하는 단계별 프로세스입니다. 워크플로우 또는 에이전트 워크플로우는 명시적인 에이전트 사용 없이 에이전트 행동을 구조화하는 방법입니다. ## LlamaIndex를 특별하게 만드는 것은 무엇인가요? LlamaIndex가 smolagents와 같은 다른 프레임워크와 유사한 일부 작업을 수행하지만, 몇 가지 주요 이점이 있습니다: - **명확한 워크플로우 시스템**: 워크플로우는 이벤트 기반 및 비동기 우선 구문을 사용하여 에이전트가 단계별로 어떻게 결정을 내려야 하는지 분해하는 데 도움이 됩니다. 이는 로직을 명확하게 구성하고 구성하는 데 도움이 됩니다. - **LlamaParse를 통한 고급 문서 파싱**: LlamaParse는 LlamaIndex를 위해 특별히 만들어졌으므로 통합이 원활하지만, 유료 기능입니다. - **많은 즉시 사용 가능한 구성 요소**: LlamaIndex는 오랫동안 존재해왔으므로 많은 다른 프레임워크와 함께 작동합니다. 이는 LLM, 검색기, 인덱스 등과 같은 많은 테스트되고 신뢰할 수 있는 구성 요소가 있음을 의미합니다. - **LlamaHub**: LlamaIndex 내에서 사용할 수 있는 이러한 구성 요소, 에이전트, 툴의 수백 개 레지스트리입니다. 이러한 모든 개념은 유용한 에이전트를 만들기 위해 다양한 시나리오에서 필요합니다. 다음 섹션에서는 이러한 개념들을 각각 자세히 살펴볼 것입니다. 개념을 마스터한 후, 우리의 학습을 사용하여 **에이전트 알프레드와 함께 적용된 사용 사례를 만들** 것입니다! LlamaIndex를 직접 다루는 것이 흥미롭지 않나요? 그럼 무엇을 기다리고 있나요? **LlamaHub를 사용하여 필요한 통합을 찾고 설치하는** 것으로 시작해봅시다! 🚀 ================================================ FILE: units/ko/unit2/llama-index/llama-hub.mdx ================================================ # LlamaHub 소개 **LlamaHub는 LlamaIndex 내에서 사용할 수 있는 수백 개의 통합, 에이전트, 툴의 레지스트리입니다.** ![LlamaHub](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/llama-hub.png) 이 강의에서 다양한 통합을 사용할 것이므로, 먼저 LlamaHub와 그것이 어떻게 우리를 도울 수 있는지 살펴보겠습니다. 필요한 구성 요소의 의존성을 찾고 설치하는 방법을 살펴보겠습니다. ## 설치 LlamaIndex 설치 지침은 [LlamaHub](https://llamahub.ai/)에서 잘 구조화된 **개요로 제공**됩니다. 처음에는 조금 압도적일 수 있지만, 대부분의 **설치 명령어는 일반적으로 기억하기 쉬운 형식**을 따릅니다: ```bash pip install llama-index-{component-type}-{framework-name} ``` [Hugging Face 추론 API 통합](https://llamahub.ai/l/llms/llama-index-llms-huggingface-api?from=llms)을 사용하여 LLM과 임베딩 구성 요소의 의존성을 설치해보겠습니다. ```bash pip install llama-index-llms-huggingface-api llama-index-embeddings-huggingface ``` ## 사용법 설치되면 사용 패턴을 볼 수 있습니다. 가져오기 경로가 설치 명령어를 따르는 것을 알 수 있을 것입니다! 아래에서 **LLM 구성 요소를 위한 Hugging Face 추론 API 사용**의 예를 볼 수 있습니다. ```python from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI import os from dotenv import load_dotenv # .env 파일 로드 load_dotenv() # 환경 변수에서 HF_TOKEN 검색 hf_token = os.getenv("HF_TOKEN") llm = HuggingFaceInferenceAPI( model_name="Qwen/Qwen2.5-Coder-32B-Instruct", temperature=0.7, max_tokens=100, token=hf_token, ) response = llm.complete("안녕하세요, 어떻게 지내시나요?") print(response) # 잘 지내고 있습니다, 오늘 어떻게 도와드릴까요? ``` 훌륭합니다, 이제 필요한 구성 요소의 통합을 찾고, 설치하고, 사용하는 방법을 알게 되었습니다. **구성 요소에 대해 더 깊이 들어가서** 우리만의 에이전트를 구축하는 데 어떻게 사용할 수 있는지 살펴보겠습니다. ================================================ FILE: units/ko/unit2/llama-index/quiz1.mdx ================================================ # 미니 퀴즈 (채점되지 않음) [[quiz1]] 지금까지 LlamaIndex에서 사용되는 주요 구성 요소와 툴에 대해 논의했습니다. **자신을 테스트하는 것**이 학습하는 가장 좋은 방법이고 [능력의 착각을 피하는](https://www.coursera.org/lecture/learning-how-to-learn/illusions-of-competence-BuFzf) 방법이므로 짧은 퀴즈를 만들어보겠습니다. 이것은 **지식을 강화해야 할 부분을 찾는** 데 도움이 될 것입니다. 이것은 선택사항 퀴즈이며 채점되지 않습니다. ### Q1: QueryEngine이란 무엇인가요? 다음 중 QueryEngine 구성 요소를 가장 잘 설명하는 것은 무엇인가요? --- ### Q2: FunctionTools의 목적은 무엇인가요? 에이전트에게 FunctionTools가 중요한 이유는 무엇인가요? --- ### Q3: LlamaIndex의 Toolspecs란 무엇인가요? Toolspecs의 주요 목적은 무엇인가요? --- ### Q4: 툴을 만들기 위해 필요한 것은 무엇인가요? 툴을 만들 때 포함해야 하는 정보는 무엇인가요? --- 이 퀴즈를 완료하신 것을 축하합니다! 🥳 일부 요소를 놓쳤다면, 지식을 강화하기 위해 챕터를 다시 읽어보세요. 통과하셨다면, 이러한 구성 요소로 더 깊이 구축할 준비가 되었습니다! ================================================ FILE: units/ko/unit2/llama-index/quiz2.mdx ================================================ # 셀프 체크 (채점되지 않음) [[quiz2]] 뭐?! 또 다른 퀴즈? 알겠습니다, 알겠습니다... 😅 하지만 이 짧은, 채점되지 않는 퀴즈는 **방금 배운 핵심 개념을 강화하는 데 도움이** 되기 위해 여기 있습니다. 이 퀴즈는 효과적인 AI 에이전트를 구축하기 위한 필수 구성 요소인 에이전트 워크플로우와 상호작용을 다룹니다. ### Q1: LlamaIndex에서 AgentWorkflow의 목적은 무엇인가요? --- ### Q2: 워크플로우의 상태를 추적하는 데 사용되는 객체는 무엇인가요? --- ### Q3: 에이전트가 이전 상호작용을 기억하게 하려면 어떤 메서드를 사용해야 하나요? --- ### Q4: 에이전트 RAG의 주요 특징은 무엇인가요? --- 이해하셨나요? 훌륭합니다! 이제 **단원에 대한 간단한 요약을 해보겠습니다!** ================================================ FILE: units/ko/unit2/llama-index/tools.mdx ================================================ # LlamaIndex에서 툴 사용하기 **명확한 툴 세트를 정의하는 것이 성능에 중요합니다.** [1단원](../../unit1/tools)에서 논의했듯이, 명확한 툴 인터페이스는 LLM이 사용하기 쉽습니다. 인간 엔지니어를 위한 소프트웨어 API 인터페이스와 마찬가지로, 툴이 어떻게 작동하는지 이해하기 쉽다면 더 많은 것을 얻을 수 있습니다. **LlamaIndex에는 네 가지 주요 유형의 툴**이 있습니다: ![툴](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/tools.png) 1. `FunctionTool`: 모든 Python 함수를 에이전트가 사용할 수 있는 툴로 변환합니다. 함수가 어떻게 작동하는지 자동으로 파악합니다. 2. `QueryEngineTool`: 에이전트가 쿼리 엔진을 사용할 수 있게 하는 툴입니다. 에이전트는 쿼리 엔진 위에 구축되므로 다른 에이전트도 툴로 사용할 수 있습니다. 3. `Toolspecs`: 커뮤니티에서 만든 툴 세트로, 종종 Gmail과 같은 특정 서비스를 위한 툴을 포함합니다. 4. `Utility Tools`: 다른 툴에서 나오는 대량의 데이터를 처리하는 데 도움이 되는 특별한 툴입니다. 아래에서 각각에 대해 더 자세히 살펴보겠습니다. ## FunctionTool 만들기 이 노트북을 따라가며 Google Colab에서 코드를 실행해볼 수 있습니다. FunctionTool은 모든 Python 함수를 래핑하고 에이전트가 사용할 수 있게 만드는 간단한 방법을 제공합니다. 동기 또는 비동기 함수를 툴에 전달할 수 있으며, 선택적으로 `name`과 `description` 매개변수도 함께 전달할 수 있습니다. 이름과 설명은 특히 중요합니다. 에이전트가 언제, 어떻게 툴을 효과적으로 사용할지 이해하는 데 도움이 되기 때문입니다. 아래에서 FunctionTool을 만드는 방법을 살펴보고 호출해보겠습니다. ```python from llama_index.core.tools import FunctionTool def get_weather(location: str) -> str: """주어진 위치의 날씨를 가져오는 데 유용합니다.""" print(f"{location}의 날씨를 가져오는 중") return f"{location}의 날씨는 맑습니다" tool = FunctionTool.from_defaults( get_weather, name="my_weather_tool", description="주어진 위치의 날씨를 가져오는 데 유용합니다.", ) tool.call("뉴욕") ``` 함수 호출이 있는 에이전트나 LLM을 사용할 때, 선택된 툴(그 툴에 대해 작성된 인수)은 툴의 목적과 인수에 대한 툴 이름과 설명에 크게 의존합니다. 함수 호출 가이드에서 함수 호출에 대해 더 알아보세요. ## QueryEngineTool 만들기 이전 단원에서 정의한 `QueryEngine`은 `QueryEngineTool` 클래스를 사용하여 쉽게 툴로 변환할 수 있습니다. 아래 예제에서 `QueryEngine`에서 `QueryEngineTool`을 만드는 방법을 살펴보겠습니다. ```python from llama_index.core import VectorStoreIndex from llama_index.core.tools import QueryEngineTool from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI from llama_index.embeddings.huggingface import HuggingFaceEmbedding from llama_index.vector_stores.chroma import ChromaVectorStore embed_model = HuggingFaceEmbedding("BAAI/bge-small-en-v1.5") db = chromadb.PersistentClient(path="./alfred_chroma_db") chroma_collection = db.get_or_create_collection("alfred") vector_store = ChromaVectorStore(chroma_collection=chroma_collection) index = VectorStoreIndex.from_vector_store(vector_store, embed_model=embed_model) llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") query_engine = index.as_query_engine(llm=llm) tool = QueryEngineTool.from_defaults(query_engine, name="some useful name", description="some useful description") ``` ## Toolspecs 만들기 `ToolSpecs`를 조화롭게 함께 작동하는 툴 모음으로 생각하세요 - 잘 정리된 전문가 툴킷처럼요. 정비사의 툴킷이 차량 수리를 위해 함께 작동하는 보완적인 툴들을 포함하는 것처럼, `ToolSpec`은 특정 목적을 위해 관련된 툴들을 결합합니다. 예를 들어, 회계 에이전트의 `ToolSpec`은 스프레드시트 기능, 이메일 기능, 계산 툴을 우아하게 통합하여 재무 작업을 정확하고 효율적으로 처리할 수 있습니다.
Google Toolspec 설치 LlamaHub 섹션에서 소개된 대로, 다음 명령어로 Google toolspec을 설치할 수 있습니다: ```python pip install llama-index-tools-google ```
이제 toolspec을 로드하고 툴 리스트로 변환할 수 있습니다. ```python from llama_index.tools.google import GmailToolSpec tool_spec = GmailToolSpec() tool_spec_list = tool_spec.to_tool_list() ``` 툴에 대한 더 자세한 보기를 얻기 위해 각 툴의 `metadata`를 살펴볼 수 있습니다. ```python [(tool.metadata.name, tool.metadata.description) for tool in tool_spec_list] ``` ### LlamaIndex의 모델 컨텍스트 프로토콜 (MCP) LlamaIndex는 [LlamaHub의 ToolSpec](https://llamahub.ai/l/tools/llama-index-tools-mcp?from=)을 통해 MCP 툴 사용도 허용합니다. 단순히 MCP 서버를 실행하고 다음 구현을 통해 사용을 시작할 수 있습니다. MCP에 대해 더 깊이 알고 싶다면 [무료 MCP 강의](https://huggingface.co/learn/mcp-course/)를 확인할 수 있습니다.
MCP Toolspec 설치 LlamaHub 섹션에서 소개된 대로, 다음 명령어로 MCP toolspec을 설치할 수 있습니다: ```python pip install llama-index-tools-mcp ```
```python from llama_index.tools.mcp import BasicMCPClient, McpToolSpec # 127.0.0.1:8000에서 실행 중인 mcp 서버가 있다고 가정하거나, mcp 클라이언트를 사용하여 자체 mcp 서버에 연결할 수 있습니다. mcp_client = BasicMCPClient("http://127.0.0.1:8000/sse") mcp_tool = McpToolSpec(client=mcp_client) # 에이전트 가져오기 agent = await get_agent(mcp_tool) # 에이전트 컨텍스트 생성 agent_context = Context(agent) ``` ## 유틸리티 툴 종종 API를 직접 쿼리하는 것은 **과도한 양의 데이터를 반환할 수 있으며**, 그 중 일부는 관련이 없거나, LLM의 컨텍스트 윈도우를 넘치거나, 사용하는 토큰 수를 불필요하게 증가시킬 수 있습니다. 아래에서 두 가지 주요 유틸리티 툴을 살펴보겠습니다. 1. `OnDemandToolLoader`: 이 툴은 기존 LlamaIndex 데이터 로더(BaseReader 클래스)를 에이전트가 사용할 수 있는 툴로 변환합니다. 툴은 데이터 로더에서 `load_data`를 트리거하는 데 필요한 모든 매개변수와 자연어 쿼리 문자열로 호출할 수 있습니다. 실행 중에 먼저 데이터 로더에서 데이터를 로드하고, 인덱싱하고(예를 들어 벡터 스토어로), 그런 다음 '온디맨드'로 쿼리합니다. 이 세 단계 모두가 단일 툴 호출에서 발생합니다. 2. `LoadAndSearchToolSpec`: LoadAndSearchToolSpec은 기존 툴을 입력으로 받습니다. 툴 스펙으로서 `to_tool_list`를 구현하며, 해당 함수가 호출되면 두 개의 툴이 반환됩니다: 로딩 툴과 검색 툴입니다. 로드 툴 실행은 기본 툴을 호출한 다음 출력을 인덱싱합니다(기본적으로 벡터 인덱스로). 검색 툴 실행은 쿼리 문자열을 입력으로 받아 기본 인덱스를 호출합니다. toolspecs와 유틸리티 툴은 LlamaHub에서 찾을 수 있습니다 이제 LlamaIndex에서 에이전트와 툴의 기본을 이해했으니, LlamaIndex를 사용하여 **구성 가능하고 관리 가능한 워크플로우를 만드는** 방법을 살펴보겠습니다! ================================================ FILE: units/ko/unit2/llama-index/workflows.mdx ================================================ # LlamaIndex에서 에이전트 워크플로우 만들기 LlamaIndex의 워크플로우는 코드를 순차적이고 관리 가능한 단계로 구성하는 구조화된 방법을 제공합니다. 이러한 워크플로우는 `Events`에 의해 트리거되는 `Steps`를 정의하여 생성되며, 이들 자체가 추가 단계를 트리거하기 위해 `Events`를 발생시킵니다. RAG 작업을 위한 LlamaIndex 워크플로우를 보여주는 알프레드를 살펴보겠습니다. ![워크플로우 개요](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/workflows.png) **워크플로우는 몇 가지 주요 이점을 제공합니다:** - 코드를 개별 단계로 명확하게 구성 - 유연한 제어 흐름을 위한 이벤트 기반 아키텍처 - 단계 간 타입 안전 통신 - 내장 상태 관리 - 간단하고 복잡한 에이전트 상호작용 모두 지원 추측하셨을 수 있듯이, **워크플로우는 전체 워크플로우에 대한 제어를 유지하면서 에이전트의 자율성 사이에서 훌륭한 균형을 제공합니다.** 그럼 우리만의 워크플로우를 만드는 방법을 배워보겠습니다! ## 워크플로우 만들기 이 노트북을 따라가며 Google Colab에서 코드를 실행해볼 수 있습니다. ### 기본 워크플로우 생성
워크플로우 패키지 설치 LlamaHub 섹션에서 소개된 대로, 다음 명령어로 워크플로우 패키지를 설치할 수 있습니다: ```python pip install llama-index-utils-workflow ```
`Workflow`를 상속하는 클래스를 정의하고 함수에 `@step` 데코레이터를 사용하여 단일 단계 워크플로우를 만들 수 있습니다. 또한 워크플로우의 시작과 끝을 나타내는 특별한 이벤트인 `StartEvent`와 `StopEvent`를 추가해야 합니다. ```python from llama_index.core.workflow import StartEvent, StopEvent, Workflow, step class MyWorkflow(Workflow): @step async def my_step(self, ev: StartEvent) -> StopEvent: # 여기서 무언가 수행 return StopEvent(result="안녕하세요, 세계!") w = MyWorkflow(timeout=10, verbose=False) result = await w.run() ``` 보시다시피, 이제 `w.run()`을 호출하여 워크플로우를 실행할 수 있습니다. ### 여러 단계 연결하기 여러 단계를 연결하기 위해 **단계 간에 데이터를 전달하는 사용자 정의 이벤트를 만듭니다.** 이를 위해 단계 간에 전달되고 첫 번째 단계의 출력을 두 번째 단계로 전송하는 `Event`를 추가해야 합니다. ```python from llama_index.core.workflow import Event class ProcessingEvent(Event): intermediate_result: str class MultiStepWorkflow(Workflow): @step async def step_one(self, ev: StartEvent) -> ProcessingEvent: # 초기 데이터 처리 return ProcessingEvent(intermediate_result="1단계 완료") @step async def step_two(self, ev: ProcessingEvent) -> StopEvent: # 중간 결과 사용 final_result = f"처리 완료: {ev.intermediate_result}" return StopEvent(result=final_result) w = MultiStepWorkflow(timeout=10, verbose=False) result = await w.run() result ``` 타입 힌팅은 워크플로우가 올바르게 실행되도록 보장하므로 여기서 중요합니다. 조금 더 복잡하게 만들어보겠습니다! ### 루프와 분기 타입 힌팅은 워크플로우의 가장 강력한 부분입니다. 더 복잡한 워크플로우를 용이하게 하기 위해 분기, 루프, 조인을 만들 수 있게 해주기 때문입니다. 합집합 연산자 `|`를 사용하여 **루프를 만드는** 예제를 보여드리겠습니다. 아래 예제에서 `LoopEvent`가 단계의 입력으로 사용되고 출력으로도 반환될 수 있음을 볼 수 있습니다. ```python from llama_index.core.workflow import Event import random class ProcessingEvent(Event): intermediate_result: str class LoopEvent(Event): loop_output: str class MultiStepWorkflow(Workflow): @step async def step_one(self, ev: StartEvent | LoopEvent) -> ProcessingEvent | LoopEvent: if random.randint(0, 1) == 0: print("나쁜 일이 발생했습니다") return LoopEvent(loop_output="1단계로 돌아갑니다.") else: print("좋은 일이 발생했습니다") return ProcessingEvent(intermediate_result="첫 번째 단계 완료.") @step async def step_two(self, ev: ProcessingEvent) -> StopEvent: # 중간 결과 사용 final_result = f"처리 완료: {ev.intermediate_result}" return StopEvent(result=final_result) w = MultiStepWorkflow(verbose=False) result = await w.run() result ``` ### 워크플로우 그리기 워크플로우를 그릴 수도 있습니다. `draw_all_possible_flows` 함수를 사용하여 워크플로우를 그려보겠습니다. 이는 워크플로우를 HTML 파일에 저장합니다. ```python from llama_index.utils.workflow import draw_all_possible_flows w = ... # 이전 섹션에서 정의된 대로 draw_all_possible_flows(w, "flow.html") ``` ![워크플로우 그리기](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/workflow-draw.png) 강의에서 다룰 마지막 멋진 트릭이 있는데, 그것은 워크플로우에 상태를 추가하는 능력입니다. ### 상태 관리 상태 관리는 워크플로우의 상태를 추적하고 싶을 때 유용하므로, 모든 단계가 동일한 상태에 접근할 수 있습니다. 단계 함수의 매개변수 위에 `Context` 타입 힌팅을 사용하여 이를 수행할 수 있습니다. ```python from llama_index.core.workflow import Context, StartEvent, StopEvent @step async def query(self, ctx: Context, ev: StartEvent) -> StopEvent: # 컨텍스트에 쿼리 저장 await ctx.store.set("query", "프랑스의 수도는 무엇인가요?") # 컨텍스트와 이벤트로 무언가 수행 val = ... # 컨텍스트에서 쿼리 검색 query = await ctx.store.get("query") return StopEvent(result=val) ``` 훌륭합니다! 이제 LlamaIndex에서 기본 워크플로우를 만드는 방법을 알게 되었습니다! 워크플로우에는 더 복잡한 뉘앙스가 있으며, LlamaIndex 문서에서 배울 수 있습니다. 하지만 `AgentWorkflow` 클래스에 의존하는 워크플로우를 만드는 다른 방법이 있습니다. 이를 사용하여 다중 에이전트 워크플로우를 만드는 방법을 살펴보겠습니다. ## 다중 에이전트 워크플로우로 워크플로우 자동화 수동 워크플로우 생성 대신 **`AgentWorkflow` 클래스를 사용하여 다중 에이전트 워크플로우를 만들** 수 있습니다. `AgentWorkflow`는 워크플로우 에이전트를 사용하여 전문화된 기능을 기반으로 협업하고 서로에게 작업을 넘길 수 있는 하나 이상의 에이전트 시스템을 만들 수 있게 해줍니다. 이를 통해 서로 다른 에이전트가 작업의 서로 다른 측면을 처리하는 복잡한 에이전트 시스템을 구축할 수 있습니다. `llama_index.core.agent`에서 클래스를 가져오는 대신, `llama_index.core.agent.workflow`에서 에이전트 클래스를 가져올 것입니다. 하나의 에이전트는 `AgentWorkflow` 생성자에서 루트 에이전트로 지정되어야 합니다. 사용자 메시지가 들어오면 먼저 루트 에이전트로 라우팅됩니다. 각 에이전트는 다음을 수행할 수 있습니다: - 툴을 사용하여 요청을 직접 처리 - 작업에 더 적합한 다른 에이전트에게 작업 넘기기 - 사용자에게 응답 반환 다중 에이전트 워크플로우를 만드는 방법을 살펴보겠습니다. ```python from llama_index.core.agent.workflow import AgentWorkflow, ReActAgent from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI # 몇 가지 툴 정의 def add(a: int, b: int) -> int: """두 숫자를 더합니다.""" return a + b def multiply(a: int, b: int) -> int: """두 숫자를 곱합니다.""" return a * b llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") # FunctionTool 없이 함수를 직접 전달할 수 있습니다 -- 함수/독스트링이 이름/설명을 위해 파싱됩니다 multiply_agent = ReActAgent( name="multiply_agent", description="두 정수를 곱할 수 있습니다", system_prompt="숫자를 곱하는 툴을 사용할 수 있는 도움이 되는 어시스턴트입니다.", tools=[multiply], llm=llm, ) addition_agent = ReActAgent( name="add_agent", description="두 정수를 더할 수 있습니다", system_prompt="숫자를 더하는 툴을 사용할 수 있는 도움이 되는 어시스턴트입니다.", tools=[add], llm=llm, ) # 워크플로우 생성 workflow = AgentWorkflow( agents=[multiply_agent, addition_agent], root_agent="multiply_agent", ) # 시스템 실행 response = await workflow.run(user_msg="5와 3을 더할 수 있나요?") ``` 에이전트 툴은 앞서 언급한 워크플로우 상태도 수정할 수 있습니다. 워크플로우를 시작하기 전에 모든 에이전트가 사용할 수 있는 초기 상태 딕셔너리를 제공할 수 있습니다. 상태는 워크플로우 컨텍스트의 상태 키에 저장됩니다. 각 새로운 사용자 메시지를 보강하는 state_prompt에 주입됩니다. 이전 예제를 수정하여 함수 호출을 세는 카운터를 주입해보겠습니다: ```python from llama_index.core.workflow import Context # 몇 가지 툴 정의 async def add(ctx: Context, a: int, b: int) -> int: """두 숫자를 더합니다.""" # 카운트 업데이트 cur_state = await ctx.store.get("state") cur_state["num_fn_calls"] += 1 await ctx.store.set("state", cur_state) return a + b async def multiply(ctx: Context, a: int, b: int) -> int: """두 숫자를 곱합니다.""" # 카운트 업데이트 cur_state = await ctx.store.get("state") cur_state["num_fn_calls"] += 1 await ctx.store.set("state", cur_state) return a * b ... workflow = AgentWorkflow( agents=[multiply_agent, addition_agent], root_agent="multiply_agent", initial_state={"num_fn_calls": 0}, state_prompt="현재 상태: {state}. 사용자 메시지: {msg}", ) # 컨텍스트와 함께 워크플로우 실행 ctx = Context(workflow) response = await workflow.run(user_msg="5와 3을 더할 수 있나요?", ctx=ctx) # 상태를 꺼내서 검사 state = await ctx.store.get("state") print(state["num_fn_calls"]) ``` 축하합니다! 이제 LlamaIndex에서 에이전트의 기본을 마스터했습니다! 🎉 지식을 확고히 하기 위해 마지막 퀴즈를 계속해보겠습니다! 🚀 ================================================ FILE: units/ko/unit2/smolagents/code_agents.mdx ================================================ # 코드를 사용하는 에이전트 만들기 코드 에이전트는 `smolagents`의 기본 에이전트 유형입니다. 이들은 파이썬 도구 호출을 생성하여 작업을 수행하며, 효율적이고 표현력 있으며 정확한 액션 표현을 달성합니다. 이러한 간소화된 접근 방식은 필요한 액션 수를 줄이고, 복잡한 작업을 단순화하며, 기존 코드 함수의 재사용을 가능하게 합니다. `smolagents`는 약 1,000줄의 코드로 구현된 경량 프레임워크를 제공합니다. ![코드 vs JSON 액션](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/code_vs_json_actions.png) 위 이미지는 논문 [Executable Code Actions Elicit Better LLM Agents](https://huggingface.co/papers/2402.01030)에서 가져왔습니다. 코드 에이전트가 왜 효과적인지 더 알고 싶다면, smolagents 문서의 이 가이드를 참고하세요. ## 왜 코드 에이전트인가요? 다단계 에이전트 프로세스에서 LLM은 일반적으로 외부 도구 호출을 포함하는 액션을 작성하고 실행합니다. 기존 방식은 도구 이름과 인자를 문자열로 지정하는 JSON 형식을 사용하며, **시스템이 어떤 도구를 실행할지 파싱해야 합니다**. 하지만 연구 결과에 따르면, **도구 호출 LLM은 직접 코드를 사용할 때 더 효과적으로 작동합니다**. 이것이 `smolagents`의 핵심 원칙이며, 위의 논문 이미지에서도 확인할 수 있습니다. 코드로 액션을 작성하면 다음과 같은 주요 장점이 있습니다: * **조합성**: 액션을 쉽게 결합하고 재사용할 수 있습니다. * **객체 관리**: 이미지와 같은 복잡한 구조를 직접 다룰 수 있습니다. * **범용성**: 계산적으로 가능한 모든 작업을 표현할 수 있습니다. * **LLM에 자연스러움**: 고품질 코드는 이미 LLM의 학습 데이터에 풍부하게 포함되어 있습니다. ## 코드 에이전트는 어떻게 동작하나요? ![https://huggingface.co/docs/smolagents/conceptual_guides/react에서 가져옴](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/smolagents/codeagent_docs.png) 위 다이어그램은 `CodeAgent.run()`이 어떻게 동작하는지 보여줍니다. 이는 1단원에서 언급한 ReAct 프레임워크를 따릅니다. `smolagents`에서 에이전트의 주요 추상화는 `MultiStepAgent`이며, 이는 핵심 빌딩 블록 역할을 합니다. `CodeAgent`는 특별한 종류의 `MultiStepAgent`입니다. `CodeAgent`는 다음과 같은 단계로 동작합니다. 기존 변수와 지식은 실행 로그에 저장되어 에이전트의 컨텍스트로 활용됩니다: 1. 시스템 프롬프트는 `SystemPromptStep`에 저장되고, 사용자 쿼리는 `TaskStep`에 기록됩니다. 2. 그 다음, 다음과 같은 while 루프가 실행됩니다: 2.1 `agent.write_memory_to_messages()` 메서드는 에이전트의 로그를 LLM이 읽을 수 있는 [채팅 메시지](https://huggingface.co/docs/transformers/main/en/chat_templating) 리스트로 변환합니다. 2.2 이 메시지들은 `Model`로 전송되어 응답을 생성합니다. 2.3 응답에서 액션을 추출하는데, 코드 에이전트이므로 파이썬 코드 조각이어야 합니다. 2.4 액션이 실행됩니다. 2.5 결과가 `ActionStep`에 메모리로 기록됩니다. 각 단계가 끝날 때, 에이전트에 함수 호출(`agent.step_callback`)이 포함되어 있다면 실행됩니다. ## 예시로 알아보기 이 노트북을 따라가며 코드를 직접 실행해볼 수 있습니다. Alfred는 웨인 가문의 저택에서 파티를 준비하고 있습니다. 모든 것이 순조롭게 진행되도록 여러분의 도움이 필요합니다. 지금까지 배운 다단계 `CodeAgent`의 동작 방식을 적용해봅시다. Alfred Party 아직 `smolagents`를 설치하지 않았다면, 다음 명령어로 설치하세요: ```bash pip install smolagents -U ``` Hugging Face Hub에 로그인하여 Serverless Inference API를 사용할 수 있도록 합니다. ```python from huggingface_hub import login login() ``` ### `smolagents`로 파티 플레이리스트 선택하기 음악은 파티의 필수 요소입니다! Alfred는 플레이리스트를 고르는 데 도움이 필요합니다. 다행히도 `smolagents`를 사용하면 웹 검색 도구를 에이전트에 추가하여 이를 해결할 수 있습니다. Alfred Playlist 모델로는 Hugging Face의 [Serverless Inference API](https://huggingface.co/docs/api-inference/index)에 접근할 수 있는 `InferenceClientModel`을 사용합니다. 기본 모델은 "Qwen/Qwen2.5-Coder-32B-Instruct"이며, 빠른 추론이 가능합니다. 허브에서 호환되는 다른 모델도 선택할 수 있습니다. 에이전트 실행은 매우 간단합니다: ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel agent = CodeAgent(tools=[DuckDuckGoSearchTool()], model=InferenceClientModel()) agent.run("웨인 저택에서 열리는 파티에 어울리는 최고의 음악 추천을 검색해줘.") ``` 이 예시를 실행하면 **워크플로우 단계의 실행 추적**이 출력됩니다. 또한 다음과 같은 파이썬 코드가 표시됩니다: ```python ─ 실행된 파싱 코드: ─────────────────────────────────────────────────────────────── results = web_search(query="배트맨 파티에 어울리는 최고의 음악") print(results) ───────────────────────────────────────────────────────────────────────────────────── ``` 몇 단계 후, Alfred가 사용할 수 있는 플레이리스트가 생성됩니다! 🎵 ### 맞춤형 도구로 메뉴 준비하기 Alfred Menu 플레이리스트를 골랐다면, 이제 손님을 위한 메뉴를 준비해야 합니다. Alfred는 여기서도 `smolagents`의 도움을 받을 수 있습니다. 아래 예시에서는 `@tool` 데코레이터를 사용해 맞춤형 함수를 도구로 등록합니다. 도구 생성에 대해서는 이후에 더 자세히 다루니, 지금은 코드를 실행해보세요. 아래 예시처럼, `@tool` 데코레이터로 도구를 만들고 `tools` 리스트에 추가합니다. ```python from smolagents import CodeAgent, tool, InferenceClientModel # 파티 상황에 맞는 메뉴를 추천하는 도구 @tool def suggest_menu(occasion: str) -> str: """ 상황에 따라 메뉴를 추천합니다. Args: occasion (str): 파티 유형. 허용 값: - "casual": 캐주얼 파티 메뉴 - "formal": 포멀 파티 메뉴 - "superhero": 슈퍼히어로 파티 메뉴 - "custom": 맞춤 메뉴 """ if occasion == "casual": return "피자, 스낵, 음료." elif occasion == "formal": return "3코스 디너, 와인, 디저트." elif occasion == "superhero": return "고에너지, 건강식 뷔페." else: return "집사만을 위한 맞춤 메뉴." # Alfred가 파티 메뉴를 준비합니다 agent = CodeAgent(tools=[suggest_menu], model=InferenceClientModel()) # 파티를 위한 포멀 메뉴 준비 agent.run("파티를 위한 포멀 메뉴를 준비해줘.") ``` 에이전트는 몇 단계 실행 후 답을 찾습니다. docstring에 허용 값을 명확히 적으면 에이전트가 `occasion` 인자 값을 올바르게 사용하도록 유도할 수 있습니다. 메뉴 준비 완료! 🥗 ### 에이전트 내에서 파이썬 import 사용하기 플레이리스트와 메뉴가 준비되었으니, 이제 남은 것은 준비 시간 계산입니다! Alfred는 모든 준비를 지금 시작하면 언제 파티가 준비될지 계산해야 합니다. 필요하다면 다른 슈퍼히어로의 도움도 받을 수 있겠죠. `smolagents`는 파이썬 코드 조각을 작성하고 실행하는 에이전트에 특화되어 있으며, 보안을 위해 샌드박스 실행을 제공합니다. **코드 실행에는 엄격한 보안 조치가 적용됩니다** — 기본적으로 허용된 목록 외의 import는 차단됩니다. 하지만 `additional_authorized_imports`에 문자열로 추가하면 import를 허용할 수 있습니다. 자세한 보안 실행 방법은 공식 [가이드](https://huggingface.co/docs/smolagents/tutorials/secure_code_execution)를 참고하세요. 아래 예시에서는 `datetime` 모듈 import를 허용합니다. ```python from smolagents import CodeAgent, InferenceClientModel import numpy as np import time import datetime agent = CodeAgent(tools=[], model=InferenceClientModel(), additional_authorized_imports=['datetime']) agent.run( """ Alfred가 파티를 준비해야 합니다. 작업 목록: 1. 음료 준비 - 30분 2. 저택 장식 - 60분 3. 메뉴 세팅 - 45분 4. 음악 및 플레이리스트 준비 - 45분 지금 바로 시작하면 파티 준비가 언제 끝날까요? """ ) ``` 이 예시들은 코드 에이전트로 할 수 있는 일의 시작에 불과합니다. 더 많은 내용은 [smolagents 문서](https://huggingface.co/docs/smolagents)에서 확인하세요. 요약하자면, `smolagents`는 파이썬 코드 조각을 작성하고 실행하는 에이전트에 특화되어 있으며, 보안 샌드박스 실행을 지원합니다. 로컬 및 API 기반 언어 모델 모두 지원하여 다양한 개발 환경에 적합합니다. ### 우리만의 파티 준비 에이전트를 허브에 공유하기 우리만의 Alfred 에이전트를 커뮤니티에 공유할 수 있다면 정말 멋지지 않을까요? 누구나 허브에서 쉽게 다운로드해 사용할 수 있습니다! `smolagents`는 완성된 에이전트를 커뮤니티에 공유하고, 다른 사람의 에이전트를 즉시 다운로드할 수 있도록 지원합니다. 방법은 다음과 같이 간단합니다: ```python # 사용자명과 저장소명을 변경하세요 agent.push_to_hub('sergiopaniego/AlfredAgent') ``` 다시 다운로드하려면 아래 코드를 사용하세요: ```python # 사용자명과 저장소명을 변경하세요 alfred_agent = agent.from_hub('sergiopaniego/AlfredAgent', trust_remote_code=True) alfred_agent.run("웨인 저택에서 열리는 파티에 어울리는 최고의 플레이리스트를 추천해줘. 파티 테마는 '빌런 가면무도회'야") ``` 공유된 에이전트는 Hugging Face Spaces에서도 바로 사용할 수 있습니다. [여기](https://huggingface.co/spaces/davidberenstein1957/smolagents-and-tools)에서 다양한 에이전트를 탐색해보세요. 예를 들어, _AlfredAgent_는 [여기](https://huggingface.co/spaces/sergiopaniego/AlfredAgent)에서 바로 사용할 수 있습니다. 아래에서 직접 체험해보세요: Alfred가 어떻게 이런 에이전트를 만들었는지 궁금하다면, 여러 도구를 통합해 아래와 같이 에이전트를 생성할 수 있습니다. 도구에 대해서는 이후에 자세히 다루니, 지금은 구조만 참고하세요: ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, FinalAnswerTool, InferenceClientModel, Tool, tool, VisitWebpageTool @tool def suggest_menu(occasion: str) -> str: """ 상황에 따라 메뉴를 추천합니다. Args: occasion: 파티 유형 """ if occasion == "casual": return "피자, 스낵, 음료." elif occasion == "formal": return "3코스 디너, 와인, 디저트." elif occasion == "superhero": return "고에너지, 건강식 뷔페." else: return "집사만을 위한 맞춤 메뉴." @tool def catering_service_tool(query: str) -> str: """ 이 도구는 고담시에서 평점이 가장 높은 케이터링 서비스를 반환합니다. Args: query: 케이터링 서비스 검색어 """ # 예시 케이터링 서비스와 평점 services = { "Gotham Catering Co.": 4.9, "Wayne Manor Catering": 4.8, "Gotham City Events": 4.7, } # 평점이 가장 높은 서비스 찾기(검색어 필터링 시뮬레이션) best_service = max(services, key=services.get) return best_service class SuperheroPartyThemeTool(Tool): name = "superhero_party_theme_generator" description = """ 이 도구는 카테고리에 따라 창의적인 슈퍼히어로 테마 파티 아이디어를 제안합니다. 고유한 파티 테마 아이디어를 반환합니다.""" inputs = { "category": { "type": "string", "description": "슈퍼히어로 파티 유형(예: 'classic heroes', 'villain masquerade', 'futuristic Gotham')", } } output_type = "string" def forward(self, category: str): themes = { "classic heroes": "Justice League Gala: 손님들이 DC 영웅으로 분장하고 '크립토나이트 펀치' 같은 테마 칵테일을 즐깁니다.", "villain masquerade": "Gotham Rogues' Ball: 손님들이 배트맨 빌런으로 분장하는 신비로운 가면무도회.", "futuristic Gotham": "Neo-Gotham Night: 배트맨 비욘드에서 영감을 받은 사이버펑크 스타일 파티, 네온 장식과 미래형 소품.", } return themes.get(category.lower(), "테마 파티 아이디어를 찾을 수 없습니다. 'classic heroes', 'villain masquerade', 'futuristic Gotham' 중에서 시도해보세요.") # Alfred가 파티 메뉴를 준비합니다 agent = CodeAgent( tools=[ DuckDuckGoSearchTool(), VisitWebpageTool(), suggest_menu, catering_service_tool, SuperheroPartyThemeTool(), FinalAnswerTool() ], model=InferenceClientModel(), max_steps=10, verbosity_level=2 ) agent.run("웨인 저택에서 열리는 파티에 어울리는 최고의 플레이리스트를 추천해줘. 파티 테마는 '빌런 가면무도회'야") ``` 이처럼 여러 도구를 결합해 `CodeAgent`를 만들면, 커뮤니티와 공유할 수 있는 궁극의 파티 플래너가 완성됩니다! 🎉 이제 여러분 차례입니다: 자신만의 에이전트를 만들어 허브에 공유해보세요! 🕵️‍♂️💡 여러분의 에이전트 프로젝트를 공유하고 싶다면, Hugging Face Hub에 space를 만들고 agents-course 태그를 달아주세요. 여러분의 작품을 기다리고 있습니다! ### OpenTelemetry와 Langfuse로 파티 준비 에이전트 추적하기 📡 Alfred는 파티 준비 에이전트를 다듬으면서 실행을 디버깅하는 데 지쳐가고 있습니다. 에이전트는 본질적으로 예측 불가능하고, 동작을 추적하기 어렵기 때문입니다. 하지만 궁극의 파티 준비 에이전트를 만들어 배포하려면, 미래의 모니터링과 분석을 위한 강력한 추적 기능이 필요합니다. 여기서도 `smolagents`가 해결책을 제공합니다! [OpenTelemetry](https://opentelemetry.io/) 표준을 채택해 에이전트 실행을 계측하고, [Langfuse](https://langfuse.com/) 및 `SmolagentsInstrumentor`를 통해 동작을 쉽게 추적·분석할 수 있습니다. 설정 방법은 다음과 같이 간단합니다! 먼저, 필요한 의존성을 설치합니다: ```bash pip install opentelemetry-sdk opentelemetry-exporter-otlp openinference-instrumentation-smolagents ``` Alfred는 이미 Langfuse 계정을 만들고 API 키를 준비했습니다. 아직 계정이 없다면 [여기](https://cloud.langfuse.com/)에서 가입하거나 [대안](https://huggingface.co/docs/smolagents/tutorials/inspect_runs)을 참고하세요. API 키를 아래와 같이 환경 변수로 설정합니다: ```python import os import base64 LANGFUSE_PUBLIC_KEY="pk-lf-..." LANGFUSE_SECRET_KEY="sk-lf-..." LANGFUSE_AUTH=base64.b64encode(f"{LANGFUSE_PUBLIC_KEY}:{LANGFUSE_SECRET_KEY}".encode()).decode() os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = "https://cloud.langfuse.com/api/public/otel" # EU 데이터 리전 # os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = "https://us.cloud.langfuse.com/api/public/otel" # US 데이터 리전 os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = f"Authorization=Basic {LANGFUSE_AUTH}" ``` 마지막으로, `SmolagentsInstrumentor`를 초기화해 추적을 시작합니다. ```python from opentelemetry.sdk.trace import TracerProvider from openinference.instrumentation.smolagents import SmolagentsInstrumentor from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter from opentelemetry.sdk.trace.export import SimpleSpanProcessor trace_provider = TracerProvider() trace_provider.add_span_processor(SimpleSpanProcessor(OTLPSpanExporter())) SmolagentsInstrumentor().instrument(tracer_provider=trace_provider) ``` 이제 Alfred는 연결 완료! 🔌 `smolagents`의 실행이 Langfuse에 기록되어, 에이전트의 동작을 완벽하게 추적할 수 있습니다. 이 설정으로 이전 실행을 다시 확인하고, 파티 준비 에이전트를 더욱 개선할 수 있습니다. 에이전트 추적 및 평가 데이터 활용법은 보너스 2단원에서 더 자세히 다룹니다. ```python from smolagents import CodeAgent, InferenceClientModel agent = CodeAgent(tools=[], model=InferenceClientModel()) alfred_agent = agent.from_hub('sergiopaniego/AlfredAgent', trust_remote_code=True) alfred_agent.run("웨인 저택에서 열리는 파티에 어울리는 최고의 플레이리스트를 추천해줘. 파티 테마는 '빌런 가면무도회'야") ``` Alfred는 이제 [여기](https://cloud.langfuse.com/project/cm7bq0abj025rad078ak3luwi/traces/995fc019255528e4f48cf6770b0ce27b?timestamp=2025-02-19T10%3A28%3A36.929Z)에서 로그를 확인하고 분석할 수 있습니다. 실행 중에 작은 오류가 발생했습니다. 로그에서 오류를 찾아볼 수 있나요? 에이전트가 어떻게 오류를 처리하고 유효한 답을 반환하는지 추적해보세요. 여기에서 오류를 직접 확인할 수 있습니다. 물론 오류는 이미 수정되었으며, 자세한 내용은 이 이슈에서 확인할 수 있습니다. 한편, [추천 플레이리스트](https://open.spotify.com/playlist/0gZMMHjuxMrrybQ7wTMTpw)가 파티 준비 분위기를 완성해줍니다. 멋지죠? 🎶 --- 이제 첫 번째 코드 에이전트를 만들었으니, **이제 smolagents에서 제공하는 두 번째 에이전트 유형인 Tool Calling Agent 만드는 법**을 배워봅시다. ## 참고 자료 - [smolagents 블로그](https://huggingface.co/blog/smolagents) - smolagents 및 코드 인터랙션 소개 - [smolagents: 좋은 에이전트 만들기](https://huggingface.co/docs/smolagents/tutorials/building_good_agents) - 신뢰성 높은 에이전트 구축을 위한 베스트 프랙티스 - [Anthropic: 효과적인 에이전트 만들기](https://www.anthropic.com/research/building-effective-agents) - 에이전트 설계 원칙 - [OpenTelemetry로 실행 공유하기](https://huggingface.co/docs/smolagents/tutorials/inspect_runs) - 에이전트 추적 설정 방법 ================================================ FILE: units/ko/unit2/smolagents/conclusion.mdx ================================================ # 결론 `smolagents` 모듈(2단원)을 마친 것을 축하합니다 🥳 이제 `smolagents`의 기본을 마스터했고, 나만의 에이전트도 만들어보았습니다! 이제 여러분은 관심 있는 문제를 해결하는 에이전트를 직접 만들 수 있는 역량을 갖추었습니다. 다음 모듈에서는 **LlamaIndex로 에이전트 만드는 법**을 배울 예정입니다. 마지막으로, **이 과정에 대한 여러분의 의견과 개선점**을 듣고 싶습니다. 피드백이 있다면 👉 [이 양식](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog)을 작성해 주세요. ### 계속 배우고, 멋진 하루 보내세요 🤗 ================================================ FILE: units/ko/unit2/smolagents/final_quiz.mdx ================================================ # 시험 시간! `smolagents` 학습을 마친 여러분, 정말 수고 많으셨습니다! 이제 퀴즈로 여러분의 지식을 점검해볼 시간입니다. 🧠 ## 안내사항 - 퀴즈는 코드 문제로 구성되어 있습니다. - 코드 조각을 완성하는 지시사항이 주어집니다. - 안내를 잘 읽고, 코드 조각을 완성해 주세요. - 각 문제마다 결과와 피드백이 제공됩니다. 🧘 **이 퀴즈는 점수화되거나 인증되지 않습니다**. 여러분이 `smolagents` 라이브러리를 잘 이해했는지, 추가 학습이 필요한지 스스로 점검하는 용도입니다. 다음 단원에서는 이 지식을 실제 사례와 프로젝트에 적용해볼 예정입니다. 시작해볼까요? ## 퀴즈 🚀 퀴즈에 직접 참여하려면 👉 [여기](https://huggingface.co/spaces/agents-course/unit2_smolagents_quiz)로 이동하세요. ================================================ FILE: units/ko/unit2/smolagents/introduction.mdx ================================================ # `smolagents` 소개 Unit 2.1 Thumbnail 이 모듈에 오신 것을 환영합니다! 여기서는 [`smolagents`](https://github.com/huggingface/smolagents) 라이브러리를 활용해 **효과적인 에이전트 만드는 법**을 배웁니다. `smolagents`는 강력한 AI 에이전트를 손쉽게 만들 수 있도록 도와주는 경량 프레임워크입니다. `smolagents`는 Hugging Face에서 제공하는 라이브러리입니다. [`저장소`](https://github.com/huggingface/smolagents)에 **별(star)**을 눌러 응원해 주세요! staring smolagents ## 모듈 개요 이 모듈에서는 `smolagents`를 활용해 지능형 에이전트를 만드는 데 필요한 핵심 개념과 실전 전략을 폭넓게 다룹니다. 수많은 오픈소스 프레임워크가 존재하는 만큼, `smolagents`의 구성 요소와 장단점을 이해하고, 언제 다른 솔루션이 더 적합할지 판단하는 것이 중요합니다. 이 단원에서는 소프트웨어 개발에 특화된 코드 에이전트, 모듈형 워크플로우를 위한 툴 호출 에이전트, 정보를 검색·종합하는 리트리벌 에이전트 등 주요 에이전트 유형을 살펴봅니다. 또한 여러 에이전트를 조합하는 방법, 비전 기능 및 웹 브라우징 통합 등 동적이고 상황 인식이 가능한 애플리케이션을 만드는 방법도 다룹니다. 이번 단원에서는 1단원에서 만난 에이전트 Alfred가 다시 등장합니다. 이번에는 `smolagents` 프레임워크를 활용해 다양한 작업을 해결합니다. Alfred는 Wayne 저택에서 파티를 준비하며 여러 과제를 해결해야 합니다. Alfred의 여정을 따라가며 `smolagents`의 핵심 개념을 함께 익혀봅시다! 이 단원에서는 `smolagents` 라이브러리로 AI 에이전트를 만드는 법을 배웁니다. 여러분의 에이전트는 데이터 검색, 코드 실행, 웹페이지 상호작용이 가능하며, 여러 에이전트를 조합해 더 강력한 시스템도 만들 수 있습니다. ![Alfred the agent](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit1/this-is-alfred.jpg) ## 목차 이 단원에서 다루는 내용은 다음과 같습니다: ### 1️⃣ [왜 smolagents를 사용할까](./why_use_smolagents) `smolagents`는 다양한 오픈소스 에이전트 프레임워크 중 하나입니다. 대안으로는 `LlamaIndex`, `LangGraph` 등이 있으며, 이 과정의 다른 모듈에서 다룹니다. `smolagents`는 특정 상황에 적합한 여러 주요 기능을 제공하지만, 프레임워크 선택 시 항상 다양한 옵션을 고려해야 합니다. 이 장에서는 `smolagents`의 장단점을 살펴보고, 프로젝트 요구에 따라 현명하게 선택할 수 있도록 도와줍니다. ### 2️⃣ [CodeAgents](./code_agents) `CodeAgents`는 `smolagents`의 기본 에이전트 유형입니다. 이들은 JSON이나 텍스트 대신 파이썬 코드를 생성해 작업을 수행합니다. 이 장에서는 CodeAgent의 목적, 동작 방식, 실전 예시를 통해 그 기능을 살펴봅니다. ### 3️⃣ [ToolCallingAgents](./tool_calling_agents) `ToolCallingAgents`는 `smolagents`가 지원하는 두 번째 에이전트 유형입니다. CodeAgent가 파이썬 코드를 생성하는 것과 달리, 이 에이전트는 시스템이 파싱·해석해야 하는 JSON/텍스트 블롭을 생성합니다. 이 장에서는 ToolCallingAgent의 동작 방식, CodeAgent와의 차이점, 사용 예시를 다룹니다. ### 4️⃣ [도구(Tools)](./tools) 1단원에서 살펴본 것처럼, 도구는 LLM이 에이전트 시스템 내에서 사용할 수 있는 함수로, 에이전트 행동의 핵심 빌딩 블록입니다. 이 장에서는 도구 생성법, 구조, `Tool` 클래스와 `@tool` 데코레이터를 활용한 다양한 구현 방법을 다룹니다. 기본 도구 상자, 커뮤니티에 도구 공유, 커뮤니티 도구 불러오기 등도 배웁니다. ### 5️⃣ [리트리벌 에이전트(Retrieval Agents)](./retrieval_agents) 리트리벌 에이전트는 모델이 지식 베이스에 접근할 수 있게 하여, 다양한 소스에서 정보를 검색·종합·추출할 수 있게 합니다. 이들은 벡터 스토어를 활용해 효율적으로 정보를 찾고, **RAG(Retrieval-Augmented Generation)** 패턴을 구현합니다. 웹 검색과 맞춤형 지식 베이스 통합, 대화 맥락 유지 등 다양한 전략을 다룹니다. ### 6️⃣ [멀티 에이전트 시스템(Multi-Agent Systems)](./multi_agent_systems) 여러 에이전트를 효과적으로 조율하는 것은 강력한 멀티 에이전트 시스템 구축의 핵심입니다. 웹 검색 에이전트와 코드 실행 에이전트 등 다양한 능력을 가진 에이전트를 조합해 더 정교한 솔루션을 만들 수 있습니다. 이 장에서는 멀티 에이전트 시스템의 설계, 구현, 관리 방법을 다룹니다. ### 7️⃣ [비전 및 브라우저 에이전트(Vision and Browser agents)](./vision_agents) 비전 에이전트는 **비전-언어 모델(VLM)**을 통합해 시각 정보를 처리·해석할 수 있습니다. 이 장에서는 VLM 기반 에이전트 설계·통합법, 이미지 기반 추론, 시각 데이터 분석, 멀티모달 상호작용 등을 다룹니다. 또한 비전 에이전트를 활용해 웹을 탐색하고 정보를 추출하는 브라우저 에이전트도 만들어봅니다. ## 참고 자료 - [smolagents 공식 문서](https://huggingface.co/docs/smolagents) - [효과적인 에이전트 만들기](https://www.anthropic.com/research/building-effective-agents) - 에이전트 아키텍처 연구 논문 - [에이전트 가이드라인](https://huggingface.co/docs/smolagents/tutorials/building_good_agents) - 신뢰성 높은 에이전트 구축을 위한 베스트 프랙티스 - [LangGraph Agents](https://langchain-ai.github.io/langgraph/) - 다양한 에이전트 구현 예시 - [Function Calling Guide](https://platform.openai.com/docs/guides/function-calling) - LLM의 함수 호출 이해하기 - [RAG 베스트 프랙티스](https://www.pinecone.io/learn/retrieval-augmented-generation/) - 효과적인 RAG 구현 가이드 ================================================ FILE: units/ko/unit2/smolagents/multi_agent_systems.mdx ================================================ # 멀티 에이전트 시스템 멀티 에이전트 시스템은 **특화된 에이전트들이 협력하여 복잡한 작업을 해결**할 수 있게 해주며, 모듈성, 확장성, 견고성을 높여줍니다. 단일 에이전트에 의존하는 대신, 각기 다른 능력을 가진 에이전트들이 작업을 분담합니다. **smolagents**에서는 다양한 에이전트를 결합해 파이썬 코드 생성, 외부 도구 호출, 웹 검색 등 다양한 작업을 수행할 수 있습니다. 이러한 에이전트들을 조율함으로써 강력한 워크플로우를 만들 수 있습니다. 일반적인 구성 예시: - **매니저 에이전트**: 작업 분배 담당 - **코드 인터프리터 에이전트**: 코드 실행 담당 - **웹 검색 에이전트**: 정보 검색 담당 아래 다이어그램은 **매니저 에이전트**가 **코드 인터프리터 도구**와 **웹 검색 에이전트**를 조율하는 간단한 멀티 에이전트 아키텍처를 보여줍니다. 웹 검색 에이전트는 `DuckDuckGoSearchTool`과 `VisitWebpageTool` 같은 도구를 활용해 정보를 수집합니다. ## 멀티 에이전트 시스템 실전 예시 멀티 에이전트 시스템은 여러 특화 에이전트가 **오케스트레이터 에이전트**의 조율 아래 협력하는 구조입니다. 이 방식은 역할이 다른 에이전트들에게 작업을 분산시켜 복잡한 워크플로우를 구현할 수 있게 해줍니다. 예를 들어, **멀티 에이전트 RAG 시스템**은 다음을 통합할 수 있습니다: - **웹 에이전트**: 인터넷 브라우징 담당 - **리트리버 에이전트**: 지식 베이스 정보 검색 담당 - **이미지 생성 에이전트**: 시각 자료 생성 담당 이 모든 에이전트는 오케스트레이터가 작업 분배와 상호작용을 관리합니다. ## 멀티 에이전트 계층 구조로 복잡한 문제 해결하기 이 노트북을 따라가며 코드를 직접 실행해볼 수 있습니다. 리셉션이 다가오고 있습니다! 여러분의 도움으로 Alfred는 거의 모든 준비를 마쳤습니다. 하지만 문제가 생겼습니다: 배트모빌이 사라졌습니다. Alfred는 대체 차량을 빨리 찾아야 합니다. 다행히 브루스 웨인의 삶을 다룬 바이오픽 영화가 몇 편 제작되었으니, Alfred는 영화 세트장에 남겨진 차량을 찾아 현대식으로 개조할 수 있을지도 모릅니다. 물론 자율주행 기능도 필수겠죠. 하지만 이 차량들은 전 세계 촬영지 어디에나 있을 수 있습니다. 그래서 Alfred는 여러분의 도움이 필요합니다. 이 문제를 해결할 수 있는 에이전트를 만들어볼까요? > 👉 전 세계 배트맨 촬영지를 모두 찾아, 고담(40.7128° N, 74.0060° W)까지 화물선(비행기)으로 이동하는 데 걸리는 시간을 계산하고, 이를 지도에 표시하세요. 이동 시간에 따라 색상을 다르게 하고, 슈퍼카 공장도 같은 방식으로 표시하세요. 함께 만들어봅시다! 이 예시에는 추가 패키지가 필요하니 먼저 설치해 주세요: ```bash pip install 'smolagents[litellm]' plotly geopandas shapely kaleido -q ``` ### 먼저 화물기 이동 시간 계산 도구를 만듭니다. ```python import math from typing import Optional, Tuple from smolagents import tool @tool def calculate_cargo_travel_time( origin_coords: Tuple[float, float], destination_coords: Tuple[float, float], cruising_speed_kmh: Optional[float] = 750.0, # 화물기 평균 속도 ) -> float: """ 두 지점(위도, 경도) 간 화물기 이동 시간을 대권거리로 계산합니다. Args: origin_coords: 출발지 (위도, 경도) 튜플 destination_coords: 도착지 (위도, 경도) 튜플 cruising_speed_kmh: 순항 속도(km/h, 기본값 750) Returns: float: 예상 이동 시간(시간 단위) Example: >>> # 시카고(41.8781° N, 87.6298° W) → 시드니(33.8688° S, 151.2093° E) >>> result = calculate_cargo_travel_time((41.8781, -87.6298), (-33.8688, 151.2093)) """ def to_radians(degrees: float) -> float: return degrees * (math.pi / 180) # 좌표 변환 lat1, lon1 = map(to_radians, origin_coords) lat2, lon2 = map(to_radians, destination_coords) # 지구 반지름(km) EARTH_RADIUS_KM = 6371.0 # haversine 공식으로 대권거리 계산 dlon = lon2 - lon1 dlat = lat2 - lat1 a = ( math.sin(dlat / 2) ** 2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2) ** 2 ) c = 2 * math.asin(math.sqrt(a)) distance = EARTH_RADIUS_KM * c # 우회 경로, 관제 등 감안해 10% 추가 actual_distance = distance * 1.1 # 비행 시간 계산(이착륙 1시간 추가) flight_time = (actual_distance / cruising_speed_kmh) + 1.0 return round(flight_time, 2) print(calculate_cargo_travel_time((41.8781, -87.6298), (-33.8688, 151.2093))) ``` ### 에이전트 설정하기 모델 제공자는 Together AI를 사용합니다. GoogleSearchTool은 [Serper API](https://serper.dev)를 사용하므로, 환경 변수 `SERPAPI_API_KEY`(provider="serpapi") 또는 `SERPER_API_KEY`(provider=serper)를 설정해야 합니다. Serp API가 없다면 `DuckDuckGoSearchTool`을 사용할 수 있지만, 속도 제한에 유의하세요. ```python import os from PIL import Image from smolagents import CodeAgent, GoogleSearchTool, InferenceClientModel, VisitWebpageTool model = InferenceClientModel(model_id="Qwen/Qwen2.5-Coder-32B-Instruct", provider="together") ``` 간단한 에이전트를 만들어 기본 리포트를 받아봅시다. ```python task = """전 세계 배트맨 촬영지를 모두 찾아, 고담(40.7128° N, 74.0060° W)까지 화물기로 이동하는 시간을 계산해 pandas 데이터프레임으로 반환하세요. 슈퍼카 공장도 같은 방식으로 포함하세요.""" ``` ```python agent = CodeAgent( model=model, tools=[GoogleSearchTool("serper"), VisitWebpageTool(), calculate_cargo_travel_time], additional_authorized_imports=["pandas"], max_steps=20, ) ``` ```python result = agent.run(task) ``` ```python result ``` 실행 결과 예시: ```python | | Location | Travel Time to Gotham (hours) | |--|------------------------------------------------------|------------------------------| | 0 | Necropolis Cemetery, Glasgow, Scotland, UK | 8.60 | | 1 | St. George's Hall, Liverpool, England, UK | 8.81 | | 2 | Two Temple Place, London, England, UK | 9.17 | | 3 | Wollaton Hall, Nottingham, England, UK | 9.00 | | 4 | Knebworth House, Knebworth, Hertfordshire, UK | 9.15 | | 5 | Acton Lane Power Station, Acton Lane, Acton, UK | 9.16 | | 6 | Queensboro Bridge, New York City, USA | 1.01 | | 7 | Wall Street, New York City, USA | 1.00 | | 8 | Mehrangarh Fort, Jodhpur, Rajasthan, India | 18.34 | | 9 | Turda Gorge, Turda, Romania | 11.89 | | 10 | Chicago, USA | 2.68 | | 11 | Hong Kong, China | 19.99 | | 12 | Cardington Studios, Northamptonshire, UK | 9.10 | | 13 | Warner Bros. Leavesden Studios, Hertfordshire, UK | 9.13 | | 14 | Westwood, Los Angeles, CA, USA | 6.79 | | 15 | Woking, UK (McLaren) | 9.13 | ``` 계획 단계(planning step)를 추가하고 프롬프트를 보강하면 더 나은 결과를 얻을 수 있습니다. 계획 단계는 에이전트가 다음 단계를 미리 생각하고 계획할 수 있게 해줍니다. ```python agent.planning_interval = 4 detailed_report = agent.run(f""" 여러분은 전문 분석가입니다. 여러 웹사이트를 방문해 종합 리포트를 작성합니다. for 루프를 활용해 여러 쿼리를 한 번에 검색하세요. 각 데이터 포인트마다 소스 URL을 방문해 수치를 확인하세요. {task} """) print(detailed_report) ``` ```python detailed_report ``` 실행 결과 예시: ```python | | Location | Travel Time (hours) | |--|--------------------------------------------------|---------------------| | 0 | Bridge of Sighs, Glasgow Necropolis, Glasgow, UK | 8.6 | | 1 | Wishart Street, Glasgow, Scotland, UK | 8.6 | ``` 이처럼 프롬프트와 계획 기능만으로도 훨씬 간결한 리포트를 얻을 수 있습니다! 모델의 컨텍스트 윈도우가 빠르게 채워집니다. **따라서 상세 검색 결과와 다른 결과를 결합하도록 요청하면 느려지고 토큰·비용이 급증할 수 있습니다.** ➡️ 시스템 구조를 개선해야 합니다. ### ✌️ 두 에이전트로 작업 분할하기 멀티 에이전트 구조는 서로 다른 하위 작업의 메모리를 분리해 두 가지 큰 이점을 제공합니다: - 각 에이전트가 핵심 작업에 집중해 성능이 향상됩니다. - 메모리 분리로 각 단계의 입력 토큰 수가 줄어, 지연과 비용이 감소합니다. 웹 검색 전담 에이전트와 이를 관리하는 매니저 에이전트로 팀을 만들어봅시다. 매니저 에이전트는 최종 리포트 작성을 위해 추가 import(`plotly`, `geopandas`, `shapely`)가 필요합니다. ```python model = InferenceClientModel( "Qwen/Qwen2.5-Coder-32B-Instruct", provider="together", max_tokens=8096 ) web_agent = CodeAgent( model=model, tools=[ GoogleSearchTool(provider="serper"), VisitWebpageTool(), calculate_cargo_travel_time, ], name="web_agent", description="웹에서 정보를 찾는 역할", verbosity_level=0, max_steps=10, ) ``` 매니저 에이전트는 더 강력한 모델 [DeepSeek-R1](https://huggingface.co/deepseek-ai/DeepSeek-R1)을 사용하고, `planning_interval`도 추가합니다. ```python from smolagents.utils import encode_image_base64, make_image_url from smolagents import OpenAIServerModel def check_reasoning_and_plot(final_answer, agent_memory): multimodal_model = OpenAIServerModel("gpt-4o", max_tokens=8096) filepath = "saved_map.png" assert os.path.exists(filepath), "saved_map.png 파일이 저장되어야 합니다!" image = Image.open(filepath) prompt = ( f"다음은 사용자 요청과 에이전트 단계입니다: {agent_memory.get_succinct_steps()}. 아래는 생성된 지도입니다." "추론 과정과 지도가 요청을 올바르게 해결하는지 확인하세요." "먼저 이유를 나열한 뒤, 최종 결정(PASS/FAIL)을 작성하세요." "너무 엄격할 필요는 없습니다. 대부분 해결했다면 PASS입니다." "지도는 px.scatter_map으로 만들어야 PASS입니다." ) messages = [ { "role": "user", "content": [ { "type": "text", "text": prompt, }, { "type": "image_url", "image_url": {"url": make_image_url(encode_image_base64(image))}, }, ], } ] output = multimodal_model(messages).content print("피드백: ", output) if "FAIL" in output: raise Exception(output) return True manager_agent = CodeAgent( model=InferenceClientModel("deepseek-ai/DeepSeek-R1", provider="together", max_tokens=8096), tools=[calculate_cargo_travel_time], managed_agents=[web_agent], additional_authorized_imports=[ "geopandas", "plotly", "shapely", "json", "pandas", "numpy", ], planning_interval=5, verbosity_level=2, final_answer_checks=[check_reasoning_and_plot], max_steps=15, ) ``` 이 팀의 구조를 시각화해봅시다: ```python manager_agent.visualize() ``` 아래와 같이 구조와 도구 사용 관계를 한눈에 볼 수 있습니다: ```python CodeAgent | deepseek-ai/DeepSeek-R1 ├── ✅ Authorized imports: ['geopandas', 'plotly', 'shapely', 'json', 'pandas', 'numpy'] ├── 🛠️ Tools: │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ │ ┃ Name ┃ Description ┃ Arguments ┃ │ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ │ calculate_cargo_travel_time │ 두 지점 간 화물기 이동 시간 계산 │ origin_coords (`array`): 출발지 좌표 │ │ │ │ │ destination_coords (`array`): 도착지 │ │ │ │ │ cruising_speed_kmh (`number`): 속도 │ │ │ final_answer │ 문제에 대한 최종 답변 제공 │ answer (`any`): 최종 답변 │ │ └─────────────────────────────┴───────────────────────────────────────┴───────────────────────────────────────┘ └── 🤖 Managed agents: └── web_agent | CodeAgent | Qwen/Qwen2.5-Coder-32B-Instruct ├── ✅ Authorized imports: [] ├── 📝 Description: 웹에서 정보를 찾는 역할 └── 🛠️ Tools: ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ Name ┃ Description ┃ Arguments ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ web_search │ 구글 웹 검색 수행 │ query (`string`): 검색어 │ │ │ │ filter_year (`integer`): 연도 제한 │ │ visit_webpage │ 웹페이지 방문 및 내용 읽기 │ url (`string`): 방문할 URL │ │ calculate_cargo_travel_time │ 두 지점 간 화물기 이동 시간 계산 │ origin_coords (`array`): 출발지 │ │ │ │ destination_coords (`array`): 도착지│ │ │ │ cruising_speed_kmh (`number`): 속도 │ │ final_answer │ 문제에 대한 최종 답변 제공 │ answer (`any`): 최종 답변 │ └─────────────────────────────┴───────────────────────────────────┴───────────────────────────────────┘ ``` ```python manager_agent.run(""" 전 세계 배트맨 촬영지를 모두 찾아, 고담(40.7128° N, 74.0060° W)까지 화물기로 이동하는 시간을 계산하세요. 슈퍼카 공장도 같은 방식으로 포함해 총 6개 이상 지점을 지도에 산점도로 표시하고, 이동 시간에 따라 색상을 다르게 하세요. 결과 이미지는 saved_map.png로 저장하세요! 지도 예시: import plotly.express as px df = px.data.carshare() fig = px.scatter_map(df, lat="centroid_lat", lon="centroid_lon", text="name", color="peak_hour", size=100, color_continuous_scale=px.colors.sequential.Magma, size_max=15, zoom=1) fig.show() fig.write_image("saved_image.png") final_answer(fig) 문자열을 코드로 처리하지 마세요. 문자열이 있으면 print로 출력하세요. """) ``` 제 실행에서는 매니저 에이전트가 웹 에이전트에게 `1. 배트맨 촬영지 검색`, `2. 슈퍼카 공장 찾기`로 작업을 분배한 뒤, 결과를 집계해 지도를 그렸습니다. 에이전트 상태에서 지도를 직접 확인해봅시다: ```python manager_agent.python_executor.state["fig"] ``` 아래와 같이 지도가 출력됩니다: ![멀티에이전트 시스템 예시 출력 지도](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/smolagents/output_map.png) ## 참고 자료 - [멀티 에이전트 시스템](https://huggingface.co/docs/smolagents/main/en/examples/multiagents) – 멀티 에이전트 시스템 개요 - [Agentic RAG란?](https://weaviate.io/blog/what-is-agentic-rag) – Agentic RAG 소개 - [Multi-Agent RAG System 🤖🤝🤖 레시피](https://huggingface.co/learn/cookbook/multiagent_rag_system) – 단계별 구축 가이드 ================================================ FILE: units/ko/unit2/smolagents/quiz1.mdx ================================================ # 소규모 퀴즈(비채점) [[quiz1]] `smolagents`에 대한 이해도를 간단한 퀴즈로 확인해봅시다! 스스로 테스트해보면 학습 내용을 강화하고, 복습이 필요한 부분을 파악하는 데 도움이 됩니다. 이 퀴즈는 선택 사항이며 점수화되지 않습니다. ### Q1: `smolagents`를 다른 프레임워크보다 선택할 때의 주요 장점은 무엇인가요? 다음 중 `smolagents` 접근 방식의 핵심 강점을 가장 잘 설명하는 문장은 무엇인가요? --- ### Q2: 어떤 상황에서 smolagents를 사용하는 것이 가장 적합할까요? 다음 중 smolagents의 특성과 가장 잘 맞는 상황은 무엇인가요? --- ### Q3: smolagents의 모델 통합 유연성에 대해 올바르게 설명한 것은? smolagents가 LLM과 상호작용하는 방식을 가장 잘 설명하는 문장을 고르세요. --- ### Q4: smolagents는 코드 기반 액션과 JSON 기반 액션에 대해 어떻게 접근하나요? 다음 중 smolagents의 액션 포맷 철학을 올바르게 설명한 문장은? --- ### Q5: smolagents가 Hugging Face Hub와 통합되어 얻을 수 있는 이점은? Hub 통합의 핵심 장점을 올바르게 설명한 문장은? --- 퀴즈를 모두 마쳤습니다! 🎉 틀린 문제가 있다면 *왜 smolagents를 사용할까* 섹션을 복습해보세요. 잘 풀었다면, 이제 smolagents의 더 고급 주제로 넘어갈 준비가 되었습니다! ================================================ FILE: units/ko/unit2/smolagents/quiz2.mdx ================================================ # 소규모 퀴즈(비채점) [[quiz2]] *Code Agents*, *Tool Calling Agents*, *Tools* 섹션에 대한 이해도를 테스트해봅시다. 이 퀴즈는 선택 사항이며 점수화되지 않습니다. --- ### Q1: smolagents에서 `@tool` 데코레이터로 도구를 만드는 것과 `Tool` 서브클래스를 만드는 것의 핵심 차이는? 두 방식의 도구 정의 차이를 가장 잘 설명하는 문장을 고르세요. @tool 데코레이터는 리트리벌 기반 도구에만 필수이고, Tool 서브클래스는 텍스트 생성 작업에만 사용된다", explain: "두 방식 모두 어떤 유형의 도구에도 사용할 수 있습니다.", }, { text: "@tool 데코레이터는 간단한 함수형 도구에 권장되고, Tool 서브클래스는 복잡한 기능이나 커스텀 메타데이터가 필요할 때 더 유연하다", explain: "정답입니다. 데코레이터 방식이 더 간단하고, 서브클래싱은 맞춤 동작에 적합합니다.", correct: true }, { text: "@tool은 멀티 에이전트 시스템에서만 쓸 수 있고, Tool 서브클래스는 단일 에이전트에만 쓸 수 있다", explain: "모든 에이전트(단일/멀티)에서 두 방식 모두 사용할 수 있습니다.", }, { text: "@tool로 함수에 데코레이터를 달면 docstring이 필요 없고, 서브클래스는 docstring을 포함하면 안 된다", explain: "두 방식 모두 명확한 docstring이 필요합니다.", } ]} /> --- ### Q2: CodeAgent는 ReAct(Reason + Act) 접근법으로 다단계 작업을 어떻게 처리하나요? CodeAgent가 일련의 단계를 실행해 문제를 푸는 방식을 올바르게 설명한 문장을 고르세요. --- ### Q3: 도구를 Hugging Face Hub에 공유할 때의 주요 장점은? 개발자가 커스텀 도구를 업로드·공유하는 가장 큰 이유를 고르세요. --- ### Q4: ToolCallingAgent와 CodeAgent의 액션 실행 방식 차이에 대해 올바른 설명은? ToolCallingAgent의 동작 방식을 가장 잘 설명한 문장을 고르세요. --- ### Q5: smolagents 기본 도구 상자에는 무엇이 포함되어 있고, 왜 사용할까요? 기본 도구 상자의 목적과 내용을 가장 잘 설명한 문장을 고르세요. --- 퀴즈를 모두 마쳤습니다! 🎉 어려웠던 문제는 *Code Agents*, *Tool Calling Agents*, *Tools* 섹션을 복습해보세요. 모두 맞췄다면, robust한 smolagents 애플리케이션을 만들 준비가 된 것입니다! ================================================ FILE: units/ko/unit2/smolagents/retrieval_agents.mdx ================================================ # 에이전틱 RAG 시스템 구축하기 코드는 이 노트북에서 따라할 수 있습니다. Google Colab에서 실행할 수 있습니다. Retrieval Augmented Generation(RAG) 시스템은 데이터 검색과 생성 모델의 능력을 결합하여 상황에 맞는 답변을 제공합니다. 예를 들어, 사용자의 질문이 검색 엔진에 전달되고, 검색된 결과가 질문과 함께 모델에 제공됩니다. 모델은 질문과 검색된 정보를 바탕으로 답변을 생성합니다. 에이전틱 RAG(검색 증강 생성)는 **자율 에이전트와 동적 지식 검색**을 결합하여 기존 RAG 시스템을 확장합니다. 기존 RAG 시스템은 LLM이 검색된 데이터를 바탕으로 답변을 생성하지만, 에이전틱 RAG는 **검색과 생성 과정을 지능적으로 제어**하여 효율성과 정확성을 높입니다. 기존 RAG 시스템의 주요 한계는 **단일 검색 단계에 의존**하고, 사용자의 질문과 직접적인 의미적 유사성에만 집중하여 관련 정보를 놓칠 수 있다는 점입니다. 에이전틱 RAG는 에이전트가 검색 쿼리를 자율적으로 생성하고, 검색 결과를 비판적으로 평가하며, 여러 번의 검색 단계를 거쳐 더 맞춤화되고 포괄적인 출력을 생성할 수 있도록 합니다. ## DuckDuckGo를 활용한 기본 검색 이제 DuckDuckGo를 사용해 웹을 검색하는 간단한 에이전트를 만들어봅시다. 이 에이전트는 정보를 검색하고, 답변을 종합하여 질문에 답합니다. 에이전틱 RAG를 활용하면 Alfred의 에이전트는 다음과 같은 일을 할 수 있습니다: * 최신 슈퍼히어로 파티 트렌드 검색 * 결과를 고급스러운 요소로 세분화 * 정보를 종합하여 완성된 계획 제안 Alfred의 에이전트가 이를 어떻게 수행하는지 살펴봅시다: ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel # 검색 도구 초기화 search_tool = DuckDuckGoSearchTool() # 모델 초기화 model = InferenceClientModel() agent = CodeAgent( model=model, tools=[search_tool], ) # 예시 사용법 response = agent.run( "Search for luxury superhero-themed party ideas, including decorations, entertainment, and catering." ) print(response) ``` 에이전트의 동작 과정: 1. **요청 분석:** Alfred의 에이전트는 쿼리의 핵심 요소(고급 슈퍼히어로 테마 파티, 장식, 엔터테인먼트, 케이터링 등)를 파악합니다. 2. **검색 수행:** DuckDuckGo를 활용해 Alfred의 고급스러운 취향에 맞는 최신 정보를 검색합니다. 3. **정보 종합:** 검색 결과를 바탕으로 파티의 모든 측면을 아우르는 실행 가능한 계획을 만듭니다. 4. **정보 저장:** 검색된 정보를 저장해, 이후 파티 준비 시 효율적으로 재활용할 수 있습니다. ## 맞춤형 지식 베이스 도구 특정 작업에는 맞춤형 지식 베이스가 매우 유용합니다. 벡터 데이터베이스에 저장된 기술 문서나 전문 지식을 쿼리하는 도구를 만들어봅시다. 의미적 검색을 통해 Alfred의 요구에 가장 적합한 정보를 찾을 수 있습니다. 벡터 데이터베이스는 텍스트나 기타 데이터를 머신러닝 모델로 임베딩(숫자 벡터)하여 저장합니다. 이를 통해 의미적으로 유사한 정보를 고차원 공간에서 찾을 수 있습니다. 이 접근법은 사전 정의된 지식과 의미적 검색을 결합해 상황에 맞는 솔루션을 제공합니다. Alfred는 전문 지식에 접근해 파티의 모든 세부 사항을 완벽하게 준비할 수 있습니다. 아래 예시에서는 BM25 검색기를 사용해 맞춤형 지식 베이스에서 파티 아이디어를 검색하는 도구를 만듭니다. `RecursiveCharacterTextSplitter`로 문서를 작은 청크로 나눠 검색 효율을 높입니다. ```python from langchain.docstore.document import Document from langchain.text_splitter import RecursiveCharacterTextSplitter from smolagents import Tool from langchain_community.retrievers import BM25Retriever from smolagents import CodeAgent, InferenceClientModel class PartyPlanningRetrieverTool(Tool): name = "party_planning_retriever" description = "Alfred의 슈퍼히어로 테마 파티를 위한 아이디어를 의미적 검색으로 찾아줍니다." inputs = { "query": { "type": "string", "description": "파티 준비나 슈퍼히어로 테마와 관련된 쿼리입니다.", } } output_type = "string" def __init__(self, docs, **kwargs): super().__init__(**kwargs) self.retriever = BM25Retriever.from_documents( docs, k=5 # 상위 5개 문서 검색 ) def forward(self, query: str) -> str: assert isinstance(query, str), "검색 쿼리는 문자열이어야 합니다." docs = self.retriever.invoke( query, ) return "\n검색된 아이디어:\n" + "".join( [ f"\n\n===== 아이디어 {str(i)} =====\n" + doc.page_content for i, doc in enumerate(docs) ] ) # 파티 준비에 관한 지식 베이스 예시 party_ideas = [ {"text": "고급 장식(금색 장식, 벨벳 커튼 등)이 있는 슈퍼히어로 테마 가면무도회.", "source": "Party Ideas 1"}, {"text": "배트맨, 원더우먼 등 슈퍼히어로 테마 음악을 연주할 전문 DJ 고용.", "source": "Entertainment Ideas"}, {"text": "케이터링 메뉴에 슈퍼히어로 이름을 붙인 요리 제공(예: '헐크의 그린 스무디', '아이언맨의 파워 스테이크').", "source": "Catering Ideas"}, {"text": "장소 곳곳에 슈퍼히어로 로고와 고담 등 도시 프로젝션 장식.", "source": "Decoration Ideas"}, {"text": "VR을 활용한 슈퍼히어로 시뮬레이션, 테마 게임 등 인터랙티브 체험 제공.", "source": "Entertainment Ideas"} ] source_docs = [ Document(page_content=doc["text"], metadata={"source": doc["source"]}) for doc in party_ideas ] # 문서를 작은 청크로 분할 text_splitter = RecursiveCharacterTextSplitter( chunk_size=500, chunk_overlap=50, add_start_index=True, strip_whitespace=True, separators=["\n\n", "\n", ".", " ", ""], ) docs_processed = text_splitter.split_documents(source_docs) # 검색 도구 생성 party_planning_retriever = PartyPlanningRetrieverTool(docs_processed) # 에이전트 초기화 agent = CodeAgent(tools=[party_planning_retriever], model=InferenceClientModel()) # 예시 사용법 response = agent.run( "Find ideas for a luxury superhero-themed party, including entertainment, catering, and decoration options." ) print(response) ``` 이 향상된 에이전트는 다음을 수행할 수 있습니다: 1. 먼저 문서에서 관련 정보 검색 2. 지식 베이스의 인사이트 결합 3. 대화 맥락을 메모리에 유지 ## 고도화된 검색 기능 에이전틱 RAG 시스템을 구축할 때, 에이전트는 다음과 같은 고급 전략을 사용할 수 있습니다: 1. **쿼리 재구성(Query Reformulation):** 원본 쿼리 대신, 문서에 더 잘 맞는 최적화된 검색어 생성 2. **쿼리 분해(Query Decomposition):** 여러 정보를 포함한 쿼리를 분해해 각각 검색 3. **쿼리 확장(Query Expansion):** 쿼리를 다양한 표현으로 확장해 여러 방식으로 검색 4. **재정렬(Reranking):** Cross-Encoder 등으로 검색 결과와 쿼리의 의미적 관련성 점수 부여 5. **다단계 검색(Multi-Step Retrieval):** 초기 결과를 바탕으로 추가 검색 반복 6. **소스 통합(Source Integration):** 웹 검색, 로컬 문서 등 다양한 소스 결합 7. **결과 검증(Result Validation):** 검색된 내용의 적합성과 정확성 평가 후 답변에 포함 효과적인 에이전틱 RAG 시스템을 위해서는 여러 측면을 신중히 고려해야 합니다. 에이전트는 **쿼리 유형과 맥락에 따라 적절한 도구를 선택**해야 하며, 메모리 시스템을 통해 대화 이력을 관리하고 중복 검색을 방지해야 합니다. 또한, 예비 전략을 마련해 주요 검색 방법이 실패해도 가치를 제공할 수 있어야 하며, 검증 단계를 통해 검색 결과의 정확성과 적합성을 보장해야 합니다. ## 참고 자료 - [Agentic RAG: turbocharge your RAG with query reformulation and self-query! 🚀](https://huggingface.co/learn/cookbook/agent_rag) - smolagents로 에이전틱 RAG 시스템을 개발하는 레시피 ================================================ FILE: units/ko/unit2/smolagents/tool_calling_agents.mdx ================================================ # 액션을 코드 스니펫 또는 JSON 블롭으로 작성하기 코드는 이 노트북에서 따라할 수 있습니다. Google Colab에서 실행할 수 있습니다. Tool Calling Agent는 `smolagents`에서 제공하는 두 번째 유형의 에이전트입니다. Python 코드를 실행하는 CodeAgent와 달리, **Tool Calling Agent는 LLM 제공업체의 내장 툴 콜링 기능**을 활용해 **JSON 구조**로 툴 호출을 생성합니다. 이는 OpenAI, Anthropic 등 많은 제공업체에서 사용하는 표준 방식입니다. 예를 들어, Alfred가 케이터링 서비스와 파티 아이디어를 검색하고 싶을 때, `CodeAgent`는 다음과 같이 Python 코드를 생성해 실행합니다: ```python for query in [ "Best catering services in Gotham City", "Party theme ideas for superheroes" ]: print(web_search(f"Search for: {query}")) ``` `ToolCallingAgent`는 대신 JSON 구조를 생성합니다: ```python [ {"name": "web_search", "arguments": "Best catering services in Gotham City"}, {"name": "web_search", "arguments": "Party theme ideas for superheroes"} ] ``` 이 JSON 블롭이 시스템에 전달되어 툴 호출이 실행됩니다. `smolagents`는 [CodeAgent가 전반적으로 더 좋은 성능을 보이기 때문에](https://huggingface.co/papers/2402.01030) 주로 CodeAgent에 초점을 맞추지만, ToolCallingAgent는 변수 처리나 복잡한 툴 호출이 필요 없는 간단한 시스템에 효과적입니다. ![Code vs JSON Actions](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/code_vs_json_actions.png) ## Tool Calling Agent는 어떻게 동작하나요? Tool Calling Agent는 CodeAgent와 동일한 다단계 워크플로우를 따릅니다([이전 섹션](./code_agents) 참고). 핵심 차이점은 **액션을 구조화하는 방식**입니다. ToolCallingAgent는 실행 가능한 코드 대신, **툴 이름과 인자를 명시한 JSON 객체**를 생성합니다. 시스템은 이 명령을 파싱해 적절한 툴을 실행합니다. ## 예시: Tool Calling Agent 실행하기 앞서 Alfred가 파티 준비를 시작했던 예시를 ToolCallingAgent로 다시 구현해보겠습니다. DuckDuckGo를 활용해 웹을 검색하는 에이전트를 만들지만, 에이전트 타입만 다르고 나머지는 프레임워크가 처리합니다: ```python from smolagents import ToolCallingAgent, DuckDuckGoSearchTool, InferenceClientModel agent = ToolCallingAgent(tools=[DuckDuckGoSearchTool()], model=InferenceClientModel()) agent.run("Search for the best music recommendations for a party at the Wayne's mansion.") ``` 에이전트의 실행 로그를 보면, `Executing parsed code:` 대신 다음과 같은 메시지가 출력됩니다: ```text ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ Calling tool: 'web_search' with arguments: {'query': "best music recommendations for a party at Wayne's │ │ mansion"} │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ``` 에이전트는 구조화된 툴 호출을 생성하고, 시스템이 이를 처리해 결과를 반환합니다. CodeAgent처럼 코드를 직접 실행하지 않습니다. 이제 두 에이전트 타입의 차이를 이해했으니, 필요에 따라 적합한 방식을 선택할 수 있습니다. Alfred의 파티 준비를 계속 이어가봅시다! 🎉 ## 참고 자료 - [ToolCallingAgent 공식 문서](https://huggingface.co/docs/smolagents/v1.8.1/en/reference/agents#smolagents.ToolCallingAgent) - ToolCallingAgent에 대한 공식 문서 ================================================ FILE: units/ko/unit2/smolagents/tools.mdx ================================================ # 도구 (Tools) [unit 1](https://huggingface.co/learn/agents-course/unit1/tools)에서 살펴본 것처럼, 에이전트는 다양한 작업을 수행하기 위해 도구를 사용합니다. `smolagents`에서 도구는 **에이전트 시스템 내에서 LLM이 호출할 수 있는 함수**로 취급됩니다. 도구와 상호작용하려면 LLM이 다음과 같은 **인터페이스 설명**을 필요로 합니다: - **이름**: 도구의 이름 - **도구 설명**: 도구가 수행하는 작업 - **입력 타입 및 설명**: 도구가 받는 인자 - **출력 타입**: 도구가 반환하는 값 예를 들어, Alfred가 Wayne Manor에서 파티를 준비할 때, 케이터링 서비스 검색부터 파티 테마 아이디어 찾기까지 다양한 정보를 수집해야 합니다. 아래는 간단한 검색 도구 인터페이스 예시입니다: - **이름:** `web_search` - **도구 설명:** 특정 쿼리로 웹을 검색합니다 - **입력:** `query` (string) - 검색어 - **출력:** 검색 결과가 담긴 문자열 이러한 도구를 사용하면 Alfred는 완벽한 파티 준비를 위해 필요한 모든 정보를 쉽게 모을 수 있습니다. 아래 애니메이션은 도구 호출이 어떻게 관리되는지 보여줍니다: ![Agentic pipeline from https://huggingface.co/docs/smolagents/conceptual_guides/react](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/Agent_ManimCE.gif) ## 도구 생성 방법 `smolagents`에서 도구는 두 가지 방식으로 정의할 수 있습니다: 1. **`@tool` 데코레이터**를 사용한 간단한 함수형 도구 2. **`Tool` 클래스를 상속한 복잡한 도구** ### `@tool` 데코레이터 `@tool` 데코레이터는 **간단한 도구를 정의할 때 권장되는 방법**입니다. 내부적으로 smolagents는 함수에서 기본 정보를 파싱합니다. 함수 이름을 명확하게 짓고, 좋은 docstring을 작성하면 LLM이 더 쉽게 사용할 수 있습니다. 이 방식에서는 다음을 지켜야 합니다: - **명확하고 설명적인 함수명** - **입력과 출력에 타입 힌트 사용** - **자세한 설명과 Args 섹션** #### 고평점 케이터링 도구 예시 Alfred Catering 코드는 이 노트북에서 따라할 수 있습니다. Google Colab에서 실행할 수 있습니다. Alfred가 파티 메뉴를 정했다면, 많은 손님을 위해 케이터링 서비스를 고용해야 합니다. Gotham에서 평점이 가장 높은 케이터링 서비스를 찾는 도구를 만들어봅시다. ```python from smolagents import CodeAgent, InferenceClientModel, tool # Gotham에서 평점이 가장 높은 케이터링 서비스를 반환하는 함수 예시 @tool def catering_service_tool(query: str) -> str: """ 이 도구는 Gotham City에서 평점이 가장 높은 케이터링 서비스를 반환합니다. Args: query: 케이터링 서비스를 찾기 위한 검색어 """ # 예시 케이터링 서비스와 평점 services = { "Gotham Catering Co.": 4.9, "Wayne Manor Catering": 4.8, "Gotham City Events": 4.7, } # 평점이 가장 높은 서비스 찾기(검색어 필터링은 생략) best_service = max(services, key=services.get) return best_service agent = CodeAgent(tools=[catering_service_tool], model=InferenceClientModel()) # 에이전트 실행 예시 result = agent.run( "Can you give me the name of the highest-rated catering service in Gotham City?" ) print(result) # 출력: Gotham Catering Co. ``` ### Python 클래스로 도구 정의하기 이 방식은 [`Tool`](https://huggingface.co/docs/smolagents/v1.8.1/en/reference/tools#smolagents.Tool) 클래스를 상속해 복잡한 도구를 만드는 방법입니다. 클래스는 함수에 메타데이터를 추가해 LLM이 효과적으로 사용할 수 있도록 도와줍니다. 이 클래스에서는 다음을 정의합니다: - `name`: 도구 이름 - `description`: 시스템 프롬프트에 들어갈 설명 - `inputs`: 입력 타입과 설명이 담긴 딕셔너리 - `output_type`: 반환 타입 - `forward`: 실제 동작을 수행하는 메서드 아래는 `Tool`을 상속해 슈퍼히어로 테마 파티 아이디어를 생성하는 도구 예시입니다. #### 슈퍼히어로 테마 파티 아이디어 생성 도구 Alfred는 Wayne Manor에서 슈퍼히어로 테마 파티를 준비합니다. 손님들을 놀라게 할 독특한 테마가 필요합니다. 아래 도구는 카테고리에 따라 창의적인 파티 아이디어를 제안합니다. ```python from smolagents import Tool, CodeAgent, InferenceClientModel class SuperheroPartyThemeTool(Tool): name = "superhero_party_theme_generator" description = """ 이 도구는 카테고리에 따라 창의적인 슈퍼히어로 테마 파티 아이디어를 제안합니다. 고유한 파티 테마 아이디어를 반환합니다.""" inputs = { "category": { "type": "string", "description": "슈퍼히어로 파티 유형(예: 'classic heroes', 'villain masquerade', 'futuristic Gotham')", } } output_type = "string" def forward(self, category: str): themes = { "classic heroes": "Justice League Gala: 손님들이 DC 영웅으로 분장하고, 'The Kryptonite Punch' 같은 테마 칵테일 제공.", "villain masquerade": "Gotham Rogues' Ball: 손님들이 배트맨 빌런으로 분장하는 미스터리 가면무도회.", "futuristic Gotham": "Neo-Gotham Night: 배트맨 비욘드에서 영감을 받은 사이버펑크 스타일 파티, 네온 장식과 미래형 소품.", } return themes.get(category.lower(), "테마를 찾을 수 없습니다. 'classic heroes', 'villain masquerade', 'futuristic Gotham' 중에서 선택해보세요.") # 도구 인스턴스화 party_theme_tool = SuperheroPartyThemeTool() agent = CodeAgent(tools=[party_theme_tool], model=InferenceClientModel()) # 에이전트 실행 예시 result = agent.run( "What would be a good superhero party idea for a 'villain masquerade' theme?" ) print(result) # 출력: "Gotham Rogues' Ball: 손님들이 배트맨 빌런으로 분장하는 미스터리 가면무도회." ``` 이 도구로 Alfred는 슈퍼히어로 테마 파티의 완벽한 호스트가 될 수 있습니다! 🦸‍♂️🦸‍♀️ ## 기본 도구 모음(Default Toolbox) `smolagents`에는 바로 사용할 수 있는 여러 기본 도구가 포함되어 있습니다. [기본 도구 모음](https://huggingface.co/docs/smolagents/guided_tour?build-a-tool=Decorate+a+function+with+%40tool#default-toolbox)에는 다음이 포함됩니다: - **PythonInterpreterTool** - **FinalAnswerTool** - **UserInputTool** - **DuckDuckGoSearchTool** - **GoogleSearchTool** - **VisitWebpageTool** Alfred는 다음과 같이 다양한 도구를 활용해 Wayne Manor에서 완벽한 파티를 준비할 수 있습니다: - `DuckDuckGoSearchTool`로 창의적인 슈퍼히어로 테마 파티 아이디어 검색 - `GoogleSearchTool`로 Gotham에서 평점이 가장 높은 케이터링 서비스 찾기 - `PythonInterpreterTool`로 좌석 배치 계산 - 모든 정보를 모아 `FinalAnswerTool`로 계획 정리 이 도구들로 Alfred는 완벽하고 매끄러운 파티를 보장할 수 있습니다. 🦇💡 ## 도구 공유 및 가져오기 **smolagents**의 강력한 기능 중 하나는 커스텀 도구를 Hub에 공유하고, 커뮤니티에서 만든 도구를 쉽게 가져올 수 있다는 점입니다. 여기에는 **HF Spaces** 및 **LangChain 도구**와의 연동도 포함되어, Alfred가 Wayne Manor에서 잊지 못할 파티를 기획하는 데 큰 도움이 됩니다. 🎭 이러한 통합을 통해 Alfred는 고급 이벤트 플래닝 도구를 활용할 수 있습니다. 예를 들어, 조명 조정, 파티 음악 추천, 케이터링 업체와의 협업 등 다양한 작업을 자동화할 수 있습니다. 아래는 이러한 기능이 파티 경험을 어떻게 향상시키는지 보여주는 예시입니다: ### 도구를 Hub에 공유하기 커스텀 도구를 커뮤니티에 공유하는 것은 매우 쉽습니다! `push_to_hub()` 메서드를 사용해 Hugging Face 계정에 업로드하면 됩니다. 예를 들어, Alfred는 자신의 `party_theme_tool`을 공유해 다른 사람들도 Gotham 최고의 케이터링 서비스를 찾을 수 있도록 도울 수 있습니다: ```python party_theme_tool.push_to_hub("{your_username}/party_theme_tool", token="") ``` ### Hub에서 도구 가져오기 다른 사용자가 만든 도구를 `load_tool()` 함수로 쉽게 가져올 수 있습니다. 예를 들어, Alfred가 AI로 파티 홍보 이미지를 만들고 싶다면, 커뮤니티에서 미리 만들어진 도구를 활용할 수 있습니다: ```python from smolagents import load_tool, CodeAgent, InferenceClientModel image_generation_tool = load_tool( "m-ric/text-to-image", trust_remote_code=True ) agent = CodeAgent( tools=[image_generation_tool], model=InferenceClientModel() ) agent.run("Generate an image of a luxurious superhero-themed party at Wayne Manor with made-up superheros.") ``` ### HF Space를 도구로 가져오기 `Tool.from_space()`를 사용해 HF Space를 도구로 가져올 수도 있습니다. 이를 통해 커뮤니티의 수천 개 Space와 연동해 이미지 생성, 데이터 분석 등 다양한 작업을 수행할 수 있습니다. 이 도구는 `gradio_client`를 통해 Space의 Gradio 백엔드와 연결되므로, 미리 pip로 설치해야 합니다. 파티를 위해 Alfred는 AI로 생성한 이미지를 파티 공지에 활용할 수 있습니다. 아래는 그 예시입니다: ```python from smolagents import CodeAgent, InferenceClientModel, Tool image_generation_tool = Tool.from_space( "black-forest-labs/FLUX.1-schnell", name="image_generator", description="Generate an image from a prompt" ) model = InferenceClientModel("Qwen/Qwen2.5-Coder-32B-Instruct") agent = CodeAgent(tools=[image_generation_tool], model=model) agent.run( "Improve this prompt, then generate an image of it.", additional_args={'user_prompt': 'A grand superhero-themed party at Wayne Manor, with Alfred overseeing a luxurious gala'} ) ``` ### LangChain 도구 가져오기 `LangChain` 프레임워크는 이후 섹션에서 자세히 다룹니다. 여기서는 smolagents 워크플로우에서 LangChain 도구를 재사용할 수 있다는 점만 알아둡시다! `Tool.from_langchain()` 메서드로 LangChain 도구를 쉽게 불러올 수 있습니다. Alfred는 Wayne Manor에서 최고의 엔터테인먼트 아이디어를 찾기 위해 LangChain 도구를 활용할 수 있습니다. ```python from langchain.agents import load_tools from smolagents import CodeAgent, InferenceClientModel, Tool search_tool = Tool.from_langchain(load_tools(["serpapi"])[0]) agent = CodeAgent(tools=[search_tool], model=model) agent.run("Search for luxury entertainment ideas for a superhero-themed event, such as live performances and interactive experiences.") ``` ### MCP 서버에서 도구 모음 가져오기 `smolagents`는 [glama.ai](https://glama.ai/mcp/servers) 또는 [smithery.ai](https://smithery.ai)에서 제공하는 수백 개 MCP 서버의 도구도 가져올 수 있습니다. MCP에 대해 더 알고 싶다면 [무료 MCP 강의](https://huggingface.co/learn/mcp-course/)를 참고하세요.
mcp 클라이언트 설치 먼저 `smolagents`의 mcp 통합을 설치해야 합니다. ```bash pip install "smolagents[mcp]" ```
MCP 서버의 도구는 ToolCollection 객체로 불러올 수 있습니다: ```python import os from smolagents import ToolCollection, CodeAgent from mcp import StdioServerParameters from smolagents import InferenceClientModel model = InferenceClientModel("Qwen/Qwen2.5-Coder-32B-Instruct") server_parameters = StdioServerParameters( command="uvx", args=["--quiet", "pubmedmcp@0.1.3"], env={"UV_PYTHON": "3.12", **os.environ}, ) with ToolCollection.from_mcp(server_parameters, trust_remote_code=True) as tool_collection: agent = CodeAgent(tools=[*tool_collection.tools], model=model, add_base_tools=True) agent.run("Please find a remedy for hangover.") ``` 이렇게 하면 Alfred는 고급 엔터테인먼트 옵션을 빠르게 찾을 수 있어, Gotham의 명사들이 잊지 못할 슈퍼히어로 파티를 즐길 수 있습니다! 🎉 ## 참고 자료 - [Tools Tutorial](https://huggingface.co/docs/smolagents/tutorials/tools) - 도구 사용법을 익힐 수 있는 튜토리얼 - [Tools Documentation](https://huggingface.co/docs/smolagents/v1.8.1/en/reference/tools) - 도구에 대한 공식 문서 - [Tools Guided Tour](https://huggingface.co/docs/smolagents/v1.8.1/en/guided_tour#tools) - 도구를 효율적으로 만들고 활용하는 단계별 가이드 - [Building Effective Agents](https://huggingface.co/docs/smolagents/tutorials/building_good_agents) - 신뢰성 높고 성능 좋은 커스텀 함수 에이전트 개발 가이드 ================================================ FILE: units/ko/unit2/smolagents/vision_agents.mdx ================================================ # smolagents로 비전 에이전트 만들기 이 섹션의 예제는 강력한 VLM(비전-언어 모델) API가 필요합니다. 우리는 GPT-4o API로 테스트했습니다. 하지만 Why use smolagents에서는 smolagents와 Hugging Face에서 지원하는 대체 솔루션도 다루고 있습니다. 다른 옵션을 탐색하고 싶다면 해당 섹션을 참고하세요. 에이전트에 시각적 능력을 부여하는 것은 텍스트 처리 이상의 실제 문제를 해결하는 데 매우 중요합니다. 웹 브라우징이나 문서 이해 등 많은 실제 과제는 풍부한 시각 정보를 분석해야 합니다. 다행히도, `smolagents`는 비전-언어 모델(VLM)을 내장 지원하여 에이전트가 이미지를 효과적으로 처리하고 해석할 수 있게 해줍니다. 이 예시에서, Wayne Manor의 집사 Alfred는 파티에 참석하는 손님들의 신원을 확인하는 임무를 맡았습니다. Alfred는 모든 손님을 알지 못할 수 있으므로, 손님의 외모에 대한 시각 정보를 검색해 신원을 확인하는 에이전트를 사용할 수 있습니다. 이를 통해 Alfred는 입장 허가 여부를 현명하게 결정할 수 있습니다. 예시를 함께 만들어봅시다! ## 에이전트 실행 시작 시 이미지 제공하기 코드는 이 노트북에서 따라할 수 있습니다. Google Colab에서 실행할 수 있습니다. 이 방식에서는 이미지를 에이전트 실행 시점에 `task_images`로 전달합니다. 에이전트는 이 이미지를 전체 실행 과정에서 활용합니다. 예를 들어, Alfred는 이전 파티에서 손님들의 이름과 함께 저장된 이미지 데이터셋을 가지고 있습니다. 새로운 방문객의 이미지를 받아, 기존 데이터셋과 비교해 입장 허가 여부를 결정할 수 있습니다. 이번에는 한 손님이 입장하려고 하는데, Alfred는 이 손님이 Wonder Woman으로 위장한 Joker일 수 있다고 의심합니다. Alfred는 신원을 확인해 원치 않는 인물이 입장하지 못하도록 해야 합니다. 예시를 만들어봅시다. 우선 이미지를 불러옵니다. 여기서는 위키피디아 이미지를 사용하지만, 실제로는 다양한 활용이 가능합니다! ```python from PIL import Image import requests from io import BytesIO image_urls = [ "https://upload.wikimedia.org/wikipedia/commons/e/e8/The_Joker_at_Wax_Museum_Plus.jpg", # Joker 이미지 "https://upload.wikimedia.org/wikipedia/en/9/98/Joker_%28DC_Comics_character%29.jpg" # Joker 이미지 ] images = [] for url in image_urls: headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" } response = requests.get(url,headers=headers) image = Image.open(BytesIO(response.content)).convert("RGB") images.append(image) ``` 이제 이미지를 준비했으니, 에이전트가 손님이 Wonder Woman인지 Joker인지 판별해줍니다. ```python from smolagents import CodeAgent, OpenAIServerModel model = OpenAIServerModel(model_id="gpt-4o") # 에이전트 인스턴스화 agent = CodeAgent( tools=[], model=model, max_steps=20, verbosity_level=2 ) response = agent.run( """ 이 사진 속 만화 캐릭터의 의상과 메이크업을 묘사해 주세요. 손님이 The Joker인지 Wonder Woman인지 알려주세요. """, images=images ) ``` 실행 결과는 다음과 같습니다(실행 환경에 따라 다를 수 있습니다): ```python { 'Costume and Makeup - First Image': ( '보라색 코트와 노란색 셔츠 위에 보라색 실크 크라바트 또는 타이.', '흰색 얼굴 분장, 과장된 이목구비, 진한 눈썹, 파란 아이섀도, 빨간 입술로 넓은 미소.' ), 'Costume and Makeup - Second Image': ( '꽃이 달린 어두운 정장, 손에 트럼프 카드를 들고 있음.', '창백한 피부, 초록색 머리, 과장된 미소의 빨간 입술.' ), 'Character Identity': '이 캐릭터는 만화에서 묘사된 The Joker와 유사합니다.' } ``` 이처럼, 결과를 통해 손님이 다른 인물로 위장했음을 알 수 있으므로, Alfred는 Joker의 입장을 막을 수 있습니다! ## 동적 검색으로 이미지 제공하기 코드는 이 Python 파일에서 따라할 수 있습니다. 이전 방식도 유용하지만, 데이터베이스에 손님이 없는 경우에는 외부에서 이미지를 동적으로 검색해야 할 수 있습니다. 예를 들어, 웹을 탐색하며 손님에 대한 이미지를 찾아 신원을 확인하는 방식입니다. 이 방식에서는 에이전트 실행 중에 이미지를 동적으로 메모리에 추가합니다. smolagents의 에이전트는 `MultiStepAgent` 클래스를 기반으로 하며, 이는 ReAct 프레임워크의 추상화입니다. 이 클래스는 다양한 변수와 지식을 여러 단계에 걸쳐 기록하는 구조적 사이클로 동작합니다: 1. **SystemPromptStep:** 시스템 프롬프트 저장 2. **TaskStep:** 사용자 쿼리 및 입력 기록 3. **ActionStep:** 에이전트의 액션 및 결과 로그 기록 이 구조적 접근법 덕분에, 에이전트는 시각 정보를 동적으로 통합하고, 변화하는 작업에 적응적으로 대응할 수 있습니다. 아래 다이어그램은 이러한 동적 워크플로우와 각 단계가 에이전트 라이프사이클에서 어떻게 통합되는지 보여줍니다. 브라우징 중에는 에이전트가 스크린샷을 찍어 `observation_images`에 저장할 수 있습니다. ![Dynamic image retrieval](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/smolagents-can-see/diagram_adding_vlms_smolagents.png) 이제 필요성을 이해했으니, 전체 예시를 만들어봅시다. 이번에는 Alfred가 손님 신원 확인 과정을 완전히 통제하고 싶어 하므로, 웹을 탐색하며 정보를 찾는 것이 적합합니다. 이를 위해 Selenium과 Helium 등 브라우저 자동화 도구가 필요합니다. 아래 명령어로 필요한 패키지를 설치하세요: ```bash pip install "smolagents[all]" helium selenium python-dotenv ``` 에이전트에는 웹 브라우징을 위한 `search_item_ctrl_f`, `go_back`, `close_popups` 등 도구가 필요합니다. 이 도구들은 실제 사용자가 웹을 탐색하는 것처럼 동작하게 해줍니다. ```python @tool def search_item_ctrl_f(text: str, nth_result: int = 1) -> str: """ 현재 페이지에서 Ctrl + F로 텍스트를 검색하고 n번째 결과로 이동합니다. Args: text: 검색할 텍스트 nth_result: 몇 번째 결과로 이동할지(기본값: 1) """ elements = driver.find_elements(By.XPATH, f"//*[contains(text(), '{text}')]") if nth_result > len(elements): raise Exception(f"{nth_result}번째 결과를 찾을 수 없습니다. (총 {len(elements)}개 일치)") result = f"'{text}'에 대해 {len(elements)}개 일치." elem = elements[nth_result - 1] driver.execute_script("arguments[0].scrollIntoView(true);", elem) result += f"{len(elements)}개 중 {nth_result}번째 요소로 포커스 이동" return result @tool def go_back() -> None: """이전 페이지로 이동합니다.""" driver.back() @tool def close_popups() -> str: """ 페이지의 모달 또는 팝업을 닫습니다. 팝업 창을 닫을 때 사용하세요! 쿠키 배너에는 동작하지 않습니다. """ webdriver.ActionChains(driver).send_keys(Keys.ESCAPE).perform() ``` 또한, 스크린샷 저장 기능도 필요합니다. 이 기능은 브라우저의 스크린샷을 찍어 `step_log.observations_images = [image.copy()]`에 저장합니다. 이를 통해 에이전트가 탐색 중 이미지를 동적으로 저장하고 활용할 수 있습니다. ```python def save_screenshot(step_log: ActionStep, agent: CodeAgent) -> None: sleep(1.0) # 자바스크립트 애니메이션 대기 driver = helium.get_driver() current_step = step_log.step_number if driver is not None: for step_logs in agent.logs: # 이전 스크린샷 정리 if isinstance(step_log, ActionStep) and step_log.step_number <= current_step - 2: step_logs.observations_images = None png_bytes = driver.get_screenshot_as_png() image = Image.open(BytesIO(png_bytes)) print(f"브라우저 스크린샷 캡처: {image.size} 픽셀") step_log.observations_images = [image.copy()] # 현재 URL 정보 업데이트 url_info = f"현재 url: {driver.current_url}" step_log.observations = url_info if step_logs.observations is None else step_log.observations + "\n" + url_info return ``` 이 함수는 `step_callback`으로 에이전트에 전달되어, 각 단계가 끝날 때마다 실행됩니다. 이를 통해 에이전트는 탐색 과정에서 스크린샷을 동적으로 저장할 수 있습니다. 이제, 브라우저를 탐색하며 시각 정보를 활용하는 비전 에이전트를 만들어봅시다. 앞서 만든 도구들과 `DuckDuckGoSearchTool`을 함께 사용합니다. 이 도구는 손님 신원 확인에 필요한 정보를 웹에서 검색하는 데 도움을 줍니다. ```python from smolagents import CodeAgent, OpenAIServerModel, DuckDuckGoSearchTool model = OpenAIServerModel(model_id="gpt-4o") agent = CodeAgent( tools=[DuckDuckGoSearchTool(), go_back, close_popups, search_item_ctrl_f], model=model, additional_authorized_imports=["helium"], step_callbacks=[save_screenshot], max_steps=20, verbosity_level=2, ) ``` 이제 Alfred는 손님 신원 확인을 위해 다음과 같이 에이전트를 실행할 수 있습니다: ```python agent.run(""" 나는 Wayne Manor의 집사 Alfred로, 파티에 참석하는 손님의 신원을 확인하는 임무를 맡고 있습니다. 한 슈퍼히어로가 Wonder Woman이라고 주장하며 입장하려고 하는데, 정말 그녀가 맞는지 확인해야 합니다. Wonder Woman의 이미지를 검색해 시각적 특징을 자세히 설명해 주세요. 또한, Wikipedia에서 그녀의 외모에 대한 주요 정보를 찾아주세요. 이 정보를 바탕으로 입장 허가 여부를 결정하겠습니다. """ + helium_instructions) ``` 여기서 `helium_instructions`는 탐색을 제어하는 특수 프롬프트로, 에이전트가 올바른 순서로 웹을 탐색하도록 유도합니다. 아래 영상에서 실제 동작을 확인할 수 있습니다: 최종 출력 예시는 다음과 같습니다: ```python Final answer: Wonder Woman은 일반적으로 빨간색과 금색의 상의, 파란색 별무늬 하의, 금색 티아라, 은색 팔찌, 황금 올가미를 착용한 모습으로 묘사됩니다. 그녀는 Themyscira의 공주이자, 인간 세계에서는 Diana Prince로 알려져 있습니다. ``` 이렇게 해서, 파티 입장 손님 신원 확인을 위한 비전 에이전트를 완성했습니다! 이제 Alfred는 올바른 손님만 입장할 수 있도록 완벽하게 준비할 수 있습니다. Wayne Manor에서 멋진 파티를 즐기세요! ## 추가 자료 - [We just gave sight to smolagents](https://huggingface.co/blog/smolagents-can-see) - 비전 에이전트 기능을 소개하는 블로그 - [Web Browser Automation with Agents 🤖🌐](https://huggingface.co/docs/smolagents/examples/web_browser) - 웹 브라우저를 활용한 에이전트 예시 - [Web Browser Vision Agent Example](https://github.com/huggingface/smolagents/blob/main/src/smolagents/vision_web_browser.py) - 웹 브라우저 비전 에이전트 예시 ================================================ FILE: units/ko/unit2/smolagents/why_use_smolagents.mdx ================================================ ![smolagents banner](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/smolagents/license_to_call.png) # smolagents를 써야 하는 이유 이 모듈에서는 [smolagents](https://huggingface.co/docs/smolagents/en/index)를 사용할 때의 장단점을 살펴보고, 여러분의 필요에 맞는 프레임워크인지 판단할 수 있도록 도와드립니다. ## `smolagents`란? `smolagents`는 간단하면서도 강력한 AI 에이전트 프레임워크입니다. LLM이 검색, 이미지 생성 등 실제 세계와 상호작용할 수 있는 _에이전시(agency)_ 를 제공합니다. unit 1에서 배운 것처럼, AI 에이전트는 LLM이 **'관찰(observations)'**을 바탕으로 **'생각(thoughts)'**을 생성해 **'행동(actions)'**을 수행하는 프로그램입니다. smolagents에서 이것이 어떻게 구현되는지 살펴봅시다. ### `smolagents`의 주요 장점 - **단순함:** 최소한의 코드 복잡성과 추상화로 프레임워크를 쉽게 이해하고, 도입 및 확장할 수 있습니다. - **유연한 LLM 지원:** Hugging Face 도구 및 외부 API와의 통합을 통해 어떤 LLM과도 연동할 수 있습니다. - **코드 우선 접근:** 액션을 직접 코드로 작성하는 Code Agent를 1급 시민으로 지원하여, 파싱 없이 도구 호출을 단순화합니다. - **HF Hub 통합:** Hugging Face Hub와의 원활한 통합으로 Gradio Spaces를 도구로 활용할 수 있습니다. ### smolagents를 언제 사용해야 할까? 이러한 장점을 고려할 때, 다른 프레임워크 대신 smolagents를 사용해야 하는 경우는 언제일까요? smolagents는 다음과 같은 상황에 이상적입니다: - **가볍고 최소한의 솔루션**이 필요할 때 - **복잡한 설정 없이 빠르게 실험**하고 싶을 때 - **애플리케이션 로직이 단순**할 때 ### 코드 vs. JSON 액션 다른 프레임워크에서는 에이전트가 액션을 JSON으로 작성하는 반면, `smolagents`는 **코드 기반 도구 호출**에 집중하여 실행 과정을 단순화합니다. 도구 호출을 위한 코드를 직접 생성하므로, JSON을 파싱해 코드를 만드는 과정이 필요 없습니다. 즉, 출력된 코드를 바로 실행할 수 있습니다. 아래 다이어그램은 이 차이를 보여줍니다: ![Code vs. JSON actions](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/code_vs_json_actions.png) Code vs JSON 액션의 차이를 다시 보고 싶다면 [Unit 1의 액션 섹션](https://huggingface.co/learn/agents-course/unit1/actions#actions-enabling-the-agent-to-engage-with-its-environment)을 참고하세요. ### smolagents의 에이전트 유형 smolagents의 에이전트는 **다단계 에이전트(multi-step agent)**로 동작합니다. 각 [`MultiStepAgent`](https://huggingface.co/docs/smolagents/main/en/reference/agents#smolagents.MultiStepAgent)는 다음을 수행합니다: - 한 번의 생각(thought) - 한 번의 도구 호출 및 실행 주요 에이전트 타입으로 **[CodeAgent](https://huggingface.co/docs/smolagents/main/en/reference/agents#smolagents.CodeAgent)**를 사용하며, 도구 호출을 JSON으로 작성하는 **[ToolCallingAgent](https://huggingface.co/docs/smolagents/main/en/reference/agents#smolagents.ToolCallingAgent)**도 지원합니다. 각 에이전트 타입은 이후 섹션에서 자세히 다룹니다. smolagents에서는 도구를 @tool 데코레이터로 감싼 Python 함수 또는 Tool 클래스로 정의합니다. ### smolagents의 모델 통합 `smolagents`는 유연한 LLM 통합을 지원하여, [특정 기준](https://huggingface.co/docs/smolagents/main/en/reference/models)을 충족하는 어떤 호출 가능한 모델도 사용할 수 있습니다. 프레임워크는 모델 연결을 단순화하는 여러 사전 정의 클래스를 제공합니다: - **[TransformersModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.TransformersModel):** 로컬 `transformers` 파이프라인을 구현해 손쉬운 통합을 지원합니다. - **[InferenceClientModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.InferenceClientModel):** [Hugging Face 인프라](https://huggingface.co/docs/api-inference/index) 또는 다양한 [서드파티 추론 제공업체](https://huggingface.co/docs/huggingface_hub/main/en/guides/inference#supported-providers-and-tasks)를 통한 [서버리스 추론](https://huggingface.co/docs/huggingface_hub/main/en/guides/inference) 호출을 지원합니다. - **[LiteLLMModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.LiteLLMModel):** [LiteLLM](https://www.litellm.ai/)을 활용한 경량 모델 연동을 지원합니다. - **[OpenAIServerModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.OpenAIServerModel):** OpenAI API 인터페이스를 제공하는 모든 서비스와 연결할 수 있습니다. - **[AzureOpenAIServerModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.AzureOpenAIServerModel):** Azure OpenAI 배포와의 통합을 지원합니다. 이러한 유연성 덕분에 개발자는 각자의 용도에 가장 적합한 모델과 서비스를 선택할 수 있으며, 실험도 쉽게 할 수 있습니다. 이제 smolagents를 왜, 언제 써야 하는지 이해했으니, 이 강력한 라이브러리를 더 깊이 탐구해봅시다! ## 참고 자료 - [smolagents 블로그](https://huggingface.co/blog/smolagents) - smolagents와 코드 상호작용 소개 ================================================ FILE: units/ko/unit4/introduction.mdx ================================================ # 마지막 Unit에 오신 것을 환영합니다[[introduction]] AI Agents Course thumbnail 에이전트 코스의 마지막 Unit에 오신 것을 환영합니다! 🎉 지금까지 여러분은 AI 에이전트의 구성 요소를 이해하고 직접 만들어보면서 **AI 에이전트에 대한 탄탄한 기초**를 다졌습니다. 이제 이 지식을 바탕으로 **강력한 에이전트를 구축**하고, 빠르게 발전하는 AI 분야의 최신 동향을 따라갈 준비가 되었습니다. 이번 Unit에서는 지금까지 배운 내용을 실제로 적용하는 데 중점을 둡니다. 이것이 여러분의 **마지막 실습 프로젝트**이며, 이 프로젝트를 완료해야 **과정 수료증**을 받으실 수 있습니다. ## 도전 과제는 무엇인가요?[[whats-the-challenge]] 여러분은 자신만의 에이전트를 만들고 **[GAIA 벤치마크](https://huggingface.co/spaces/gaia-benchmark/leaderboard)의 일부를 사용해 성능을 평가**하게 됩니다. 과정을 성공적으로 수료하려면 여러분의 에이전트가 벤치마크에서 **30% 이상**의 점수를 받아야 합니다. 이 목표를 달성하면 여러분의 전문성을 공식적으로 인정하는 **수료 증명서**를 받게 됩니다. 🏅 또한, 다른 동료들과 비교하여 자신의 순위를 확인해보세요! 전용 **[학생 리더보드](https://huggingface.co/spaces/agents-course/Students_leaderboard)**에서 점수를 제출하고 커뮤니티의 진행 상황을 확인할 수 있습니다. > ** 🚨 주의: 심화 및 실습 중심 Unit** > > 이번 Unit은 이전보다 더 실용적이고 실습 위주로 진행된다는 점을 유의해 주세요. 이 섹션을 성공적으로 마치려면 **더 높은 수준의 코딩 지식**이 필요하며, 이전 파트와 비교해 **명시적인 설명이 적으므로** 스스로 과제를 해결해 나가야 합니다. 흥미진진한가요? 이제 시작해봅시다! 🚀 ================================================ FILE: units/ru-RU/_toctree.yml ================================================ - title: Раздел 0. Добро пожаловать на курс! sections: - local: unit0/introduction title: Добро пожаловать на курс 🤗 - local: unit0/onboarding title: Вводная часть - local: unit0/discord101 title: (Необязательно) Discord 101 - title: Прямой эфир 1. Как работает курс, вопросы и ответы sections: - local: communication/live1 title: Прямой эфир 1. Как работает курс, вопросы и ответы - title: Раздел 1. Введение в Агентов sections: - local: unit1/introduction title: Введение - local: unit1/what-are-agents title: Что такое Агент? - local: unit1/quiz1 title: Быстрый тест 1 - local: unit1/what-are-llms title: Что такое LLM? - local: unit1/messages-and-special-tokens title: Сообщения и специальные токены - local: unit1/tools title: Что такое инструменты? - local: unit1/quiz2 title: Быстрый тест 2 - local: unit1/agent-steps-and-structure title: Понимание ИИ агентов через цикл "Мысль-Действие-Наблюдение" - local: unit1/thoughts title: Мышление, внутренние рассуждения и подход Re-Act - local: unit1/actions title: Действия, позволяющие агенту взаимодействовать с окружающей средой - local: unit1/observations title: Наблюдение, интеграция обратной связи для Осмысления и Адаптации - local: unit1/dummy-agent-library title: Библиотека фиктивного агента - local: unit1/tutorial title: Давайте создадим нашего первого агента используя Smolagents - local: unit1/final-quiz title: Раздел 1 Финальный тест - local: unit1/get-your-certificate title: Получите свой сертификат - local: unit1/conclusion title: Заключение - title: Бонусный раздел 1. Дообучение LLM для вызова функций sections: - local: bonus-unit1/introduction title: Введение - local: bonus-unit1/what-is-function-calling title: Что такое вызов функции? - local: bonus-unit1/fine-tuning title: Давайте дообучим вашу модель для вызова функций - local: bonus-unit1/conclusion title: Заключение - title: Когда будут опубликованы следующие шаги? sections: - local: communication/next-units title: Следующие разделы ================================================ FILE: units/ru-RU/bonus-unit1/conclusion.mdx ================================================ # Заключение [[conclusion]] Поздравляем вас с завершением этого первого бонусного раздела 🥳. Вы только что **овладели пониманием вызова функций и тем, как дообучить свою модель вызову функций**! Если у нас и есть теперь совет, то это попробовать **дообучить другие модели**. **Лучший способ учиться - это пробовать**. В следующем разделе вы узнаете, как использовать **передовые фреймворки, такие как `smolagents`, `LlamaIndex` и `LangGraph`**. Наконец, мы хотели бы **узнать, что вы думаете о курсе и как мы можем его улучшить**. Если у вас есть обратная связь, пожалуйста, 👉 [заполните эту форму](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ### Продолжайте учиться, оставайтесь потрясающими 🤗 ================================================ FILE: units/ru-RU/bonus-unit1/fine-tuning.mdx ================================================ # Давайте дообучим вашу модель для вызова функций Теперь мы готовы к дообучению нашей первой модели для вызова функций 🔥. ## Как обучить нашу модель вызову функций? > Ответ: Нам нужны **данные**. Обучение модели можно разделить на 3 шага: 1. **Модель предварительно обучается на большом количестве данных**. Результатом этого шага является **предварительно обученная модель**. Например, [google/gemma-2-2b](https://huggingface.co/google/gemma-2-2b). Это базовая модель, которая умеет только **предсказывать следующий токен, не имеющая хороших способностей к следованию инструкциям**. 2. Затем, чтобы модель была полезна в контексте чата, ее необходимо **дообучить** следовать инструкциям. На этом этапе она может быть обучена создателями модели, сообществом разработчиков, вами или всеми желающими. Например, [google/gemma-2-2b-it](https://huggingface.co/google/gemma-2-2b-it) это инструктивно дообученная модель от Google Tea, созданная в рамках проекта Gemma. 3. Затем модель может быть **выровнена (aligned)** в соответствии с предпочтениями создателя. Например, модель чата службы поддержки, которая никогда не должна быть невежливой с клиентами. Обычно полноценный продукт вроде Gemini или Mistral **проходит все 3 этапа**, в то время как модели, которые вы можете найти на Hugging Face, прошли один или несколько этапов этого обучения. В этом руководстве мы создадим модель вызова функций на основе [google/gemma-2-2b-it](https://huggingface.co/google/gemma-2-2b-it). Мы выбрали дообученую модель [google/gemma-2-2b-it](https://huggingface.co/google/gemma-2-2b-it) вместо базовой модели [google/gemma-2-2b](https://huggingface.co/google/gemma-2-2b), потому что дообученная модель лучше подходит для нашего случая использования. Если начать с предварительно обученной модели, ** потребуется больше тренировок, чтобы научить модель следовать инструкциям, общаться в чате И вызывать функции**. Начиная с инструктивно дообученной модели, **мы минимизируем количество информации, которое необходимо изучить нашей модели**. ## LoRA (Low-Rank Adaptation of Large Language Models) LoRA (Low-Rank Adaptation of Large Language Models, Низкоранговая Адаптация Больших Языковых Моделей) это популярная и легковесная техника обучения, которая значительно **сокращает количество обучаемых параметров**. Она работает путем **вставки меньшего количества новых весов в качестве адаптера в модель для обучения**. Это делает обучение с LoRA намного быстрее, экономит память и создает меньшие веса модели (несколько сотен мегабайт), которые легче хранить и распространять. Инференс LoRA LoRA работает путем добавления пар матриц рангового разложения в слои трансформеров, обычно сосредоточенных на линейных слоях. Во время обучения мы "замораживаем" остальную часть модели и обновляем веса только недавно добавленных адаптеров. Таким образом, количество параметров, которые нам нужно обучить, значительно уменьшается, поскольку нам нужно обновлять только веса адаптеров. Во время инференса входные данные передаются в адаптер и базовую модель или эти веса адаптера могут быть объединены с базовой моделью, что не приводит к дополнительным затратам времени. LoRA особенно полезна для адаптации **больших** языковых моделей к конкретным задачам или доменам при сохранении управляемых требований к ресурсам. Это помогает сократить объем памяти, требуемый для обучения модели. Если вы хотите узнать больше о том, как работает LoRA, ознакомьтесь с этим [руководством](https://huggingface.co/learn/nlp-course/chapter11/4?fw=pt). ## Дообучение модели для вызова функций Вы можете получить доступ к учебному блокноту 👉 [здесь](https://huggingface.co/agents-course/notebooks/blob/main/bonus-unit1/bonus-unit1.ipynb). Затем нажмите на Open In Colab, чтобы запустить его в Colab Notebook. ================================================ FILE: units/ru-RU/bonus-unit1/introduction.mdx ================================================ # Введение ![Бонусный раздел 1 Миниатюра](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit1/thumbnail.jpg) Добро пожаловать в первый **Бонусный раздел**, в котором вы научитесь **дообучать Большую Языковую Модель (LLM) вызову функций**. С точки зрения LLM, вызов функций быстро становится *обязательной* техникой. Идея заключается в том, что вместо того, чтобы полагаться только на подходы, основанные на подсказках, как мы делали в разделе 1, вызов функций обучает вашу модель **предпринимать действия и интерпретировать наблюдения на этапе обучения**, делая ваш AI более надежным. > **Когда мне следует выполнить этот Бонусный раздел?** > > Этот раздел является **опциональным** и более продвинутым, чем Раздел 1, поэтому не стесняйтесь либо выполнить этот раздел сейчас, либо вернуться к нему, когда ваши знания улучшатся благодаря этому курсу. > >Но не волнуйтесь, в этом бонусном разделе собрана вся необходимая информация, поэтому мы расскажем вам обо всех основных концепциях дообучения модели вызову функций, даже если вы еще не изучили механизм дообучения. Лучший способ для вас пройти этот Бонусный Раздел - это: 1. Знать, как дообучить LLM трансформер, если это не так [изучите это](https://huggingface.co/learn/nlp-course/chapter3/1?fw=pt) 2. Знать, как использовать `SFTTrainer` для дообучения нашей модели, чтобы узнать об этом больше [ изучите документацию](https://huggingface.co/learn/nlp-course/en/chapter11/1) --- ## Что вы узнаете 1. **Вызов функций** Как современные **LLM эффективно структурируют свои диалоги, позволяя запускать **Инструменты**. 2. **LoRA (Low-Rank Adaptation)**. **Легкий и эффективный** метод дообучения, сокращающий накладные расходы на вычисления и хранение данных. LoRA делает обучение больших моделей *быстрым, дешевым и простым* в развертывании. 3. **Цикл «Мысль → Действие → Наблюдение» в моделях вызова функций Простой, но мощный подход к структурированию того, как ваша модель решает, когда (и как) вызывать функции, отслеживать промежуточные шаги и интерпретировать результаты, полученные от внешних инструментов или API. 4. **Новые специальные токены**. Мы введем **специальные маркеры**, которые помогут модели различать: - Внутренние рассуждения "цепочки мыслей" - Исходящие вызовы функций - Ответы, поступающие от внешних инструментов --- К концу этого раздела вы сможете: - **Понимать** внутреннюю работу API, когда речь идет об инструментах. - **Дообучать** модели с помощью техник LoRA. - Имплементировать** и **модифицировать** цикл "Мысль → Действие → Наблюдение" для создания надежных и поддерживаемых рабочих процессов вызова функций. - **Разрабатывать и использовать** специальные токены, чтобы легко отделить внутренние рассуждения модели от ее внешних действий. И вы **доработаете свою собственную модель для вызова функций** 🔥. Давайте погрузимся в **вызов функций**! ================================================ FILE: units/ru-RU/bonus-unit1/what-is-function-calling.mdx ================================================ # Что такое вызов функции? Вызов функций - это **способ, с помощью которого LLM может выполнять действия в своем окружении**. Впервые он был [введен в GPT-4](https://openai.com/index/function-calling-and-other-api-updates/), и затем был воспроизведен в других моделях. Как и инструменты агента, вызов функций дает модели возможность **осуществлять действия в своем окружении**. Однако способность к вызову функций **приобретается моделью в процессе обучения**, и она **меньше зависит от подсказок, чем другие техники агентов**. В разделе 1 Агент **не учился использовать инструменты**, мы просто предоставили список, и мы полагались на то, что модель **способна обобщить определение плана с помощью этих инструментов**. В то время как здесь агент **дообучается (тренируется) использовать инструменты с помощью вызова функций**. ## Как модель "учится" выполнять то или иное действие? В первом разделе мы рассмотрели общий процесс работы агента. После того как пользователь предоставит агенту некоторые инструменты и сформулирует запрос, модель выполнит следующий цикл: 1. *Рассуждение* : Какое действие (действия) мне нужно предпринять, чтобы выполнить поставленную задачу. 2. *Действие* : Сформирует действие с нужным параметром и остановите генерацию. 3. *Наблюдение* : Получить результат выполнения. В "типичном" диалоге с моделью через API, диалог будет чередоваться сообщениями пользователя и ассистента следующим образом: ```python conversation = [ {"role": "user", "content": "Мне нужна помощь с моим заказом"}, {"role": "assistant", "content": "Я буду рад помочь. Не могли бы вы сообщить номер вашего заказа?"}, {"role": "user", "content": "Это ЗАКАЗ-123"}, ] ``` Вызов функций привносит **новые роли в диалог**! 1. Одна новая роль для **Действия** 2. Одна новая роль для **Наблюдения** Если мы возьмем [Mistral API](https://docs.mistral.ai/capabilities/function_calling/) в качестве примера, это будет выглядеть так: ```python conversation = [ { "role": "user", "content": "Каков статус моей транзакции T1001?" }, { "role": "assistant", "content": "", "function_call": { "name": "retrieve_payment_status", "arguments": "{\"transaction_id\": \"T1001\"}" } }, { "role": "tool", "name": "retrieve_payment_status", "content": "{\"status\": \"Paid\"}" }, { "role": "assistant", "content": "Ваша транзакция T1001 была успешно оплачена." } ] ``` > ... Но вы сказали, что есть новая роль для вызова функций? **Да и нет**, в этом случае, как и во многих других API, модель форматирует действие, которое нужно выполнить, как сообщение "ассистенту". Затем шаблон чата представит это в виде **специальных токенов** для вызова функций. - `[AVAILABLE_TOOLS]` - начать список доступных инструментов - `[/AVAILABLE_TOOLS]` - завершить список доступных инструментов - `[TOOL_CALLS]` - Сделать вызов инструмента (т.е. выполнить "Действие") - `[TOOL_RESULTS]` - "Наблюдать" результат действия - `[/TOOL_RESULTS]` - Завершение наблюдение (т.е. модель может снова декодировать) Мы еще поговорим о вызовах функций в этом курсе, но если вы хотите погрузиться глубже, то можете ознакомиться с [этим отличным разделом документации](https://docs.mistral.ai/capabilities/function_calling/) --- Теперь, когда мы узнали, что такое вызов функций и как он работает, давайте **добавим некоторые возможности вызова функций к модели, которая еще не имеет таких возможностей**: **"google/gemma-2-2b-it"**, добавив в модель несколько новых специальных токенов. Чтобы сделать это, **нам нужно сначала понять, что такое дообучение и LoRA**. ================================================ FILE: units/ru-RU/communication/live1.mdx ================================================ # Live 1: Как работает курс и первые ответы на вопросы В этой первой прямой трансляции курса по Агентам мы рассказали о том, как **работает** курс (объем, разделы, задачи и многое другое), и ответили на ваши вопросы. Чтобы узнать, когда запланирован следующая прямая трансляция, проверьте наш сервер **Discord**. Мы также отправим вам электронное письмо. Если вы не сможете принять участие, не волнуйтесь, мы **записываем все прямые трансляции**. ================================================ FILE: units/ru-RU/communication/next-units.mdx ================================================ # Когда будут опубликованы следующие разделы? Вот график публикации: Следующие разделы Не забудьте записаться на курс! Подписавшись, **мы сможем присылать вам ссылки по мере публикации каждого раздела, а также обновления и подробности о предстоящих соревнованиях**. Продолжайте учиться, оставайтесь потрясающими 🤗 ================================================ FILE: units/ru-RU/unit0/discord101.mdx ================================================ # (Необязательно) Discord 101 [[discord-101]] Этикет Discord Это руководство поможет вам начать работу с Discord, бесплатной чат-платформой, популярной в игровых и ML-сообществах. Присоединяйтесь к Discord-серверу сообщества Hugging Face, которое **состоит из более чем 100 000 участников**, нажав здесь. Это отличное место для общения с другими людьми! ## Курс Агенты в Discord-сообществе Hugging Face Начало работы в Discord может быть немного сложным, поэтому вот краткое руководство, которое поможет вам сориентироваться. На сервере Сообщества HF собралось активное сообщество с интересами в различных областях, предлагающее возможности для обучения через обсуждения статей, мероприятия и многое другое. После [регистрации](http://hf.co/join/discord) представьтесь в канале `#introduce-yourself`. Мы создали 4 канала для курса по Агентам: - `agents-course-announcements`: для получения **последней информации о курсе**. - `🎓-agents-course-general`: для **обсуждения общих вопросов и свободного общения**. - `agents-course-questions`: чтобы **задавать вопросы и помочь своим однокурсникам**. - `agents-course-showcase`: для **демонстрации своих лучших агентов** . Кроме того, вам могут пригодится: - `smolagents`: для **обсуждения и поддержки библиотеки**. ## Советы по эффективному использованию Discord ### Как присоединиться к серверу Если вы не очень хорошо знакомы с Discord, вам стоит заглянуть в это руководство, чтобы узнать как присоединиться к серверу. Вот краткое описание шагов: 1. Нажмите на cсылку-приглашение. 2. Войдите в Discord, используя свою учетную запись, или создайте ее, если у вас ее еще нет. 3. Убедитесь, что вы не являетесь ИИ агентом! 4. Задайте свой псевдоним и аватар. 5. Нажмите "Присоединиться к серверу". ### Как эффективно использовать Discord Вот несколько советов по эффективному использованию Discord: - **Голосовые каналы** доступны, хотя чаще всего используется текстовый чат. - Вы можете форматировать текст в стиле **markdown**, что особенно удобно при написании кода. Обратите внимание, что стиль markdown не так хорошо работает со ссылками. - Для упорядочивания обсуждений следует открывать темы для организации **длинных разговоров**. Мы надеемся, что это руководство будет вам полезно! Если у вас возникнут вопросы, не стесняйтесь задавать их нам в Discord 🤗. ================================================ FILE: units/ru-RU/unit0/introduction.mdx ================================================ # Добро пожаловать на курс 🤗 ИИ Агенты [[introduction]] Community translation banner
Миниатюра курса AI Агенты
Фон изображения был сгенерирован с помощью Scenario.com
Добро пожаловать на самую захватывающую тему в ИИ на сегодняшний день: **Агенты**! Этот бесплатный курс проведет вас по пути **от новичка до эксперта** в понимании, использовании и создании ИИ агентов. Этот первый блок поможет вам освоиться в материале: - Ознакомьтесь с **учебным планом курса**. - **Выберите путь**, по которому вы собираетесь идти (самооценка или процесс сертификации). - **Получите дополнительную информацию о процессе сертификации и сроках**. - Познакомьтесь с командой, создавшей этот курс. - Создайте свою учетную запись **Hugging Face**. - **Зарегистрируйтесь на нашем сервере Discord** и познакомьтесь со своими одноклассниками и с нами. Давайте начнем! ## Что ожидать от этого курса? [[expect]] В этом курсе вы узнаете: - 📖 Изучите AI агентов в **теории, дизайне и на практике.** - 🧑‍💻 Научитесь **использовать известные библиотеки ИИ-агентов**, такие как [smolagents](https://huggingface.co/docs/smolagents/en/index), [LangChain](https://www.langchain.com/), и [LlamaIndex](https://www.llamaindex.ai/). - 💾 **Поделитесь своими агентами** на Hugging Face Hub и изучите агентов, созданных сообществом. - 🏆 Примите участие в испытаниях, где вы будете **оценивать своих агентов в сравнении с агентами других студентов.** - 🎓 Выполнив задания, вы **получите сертификат об окончании курса.** И многое другое! В конце этого курса вы поймете, **как работают агенты и как создавать свои собственных агентов с помощью новейших библиотек и инструментов**. Не забудьте **записаться на курс!** (Мы с уважением относимся к вашей конфиденциальности. Мы собираем ваш адрес электронной почты, чтобы **высылать вам ссылки, когда каждый блок будет опубликован, и предоставлять вам информацию о задачах и обновлениях).** ## Как выглядит курс? [[course-look-like]] Курс состоит из: - *Фундаментальные разделы*: здесь вы изучите **концепции агентов в теории**. - *Практические занятия: здесь вы научитесь **использовать готовые библиотеки агентов ИИ** для обучения агентов в уникальных условиях. Эти практические секции будут представлять собой **пространства (Spaces) Hugging Face** с предварительно настроенной средой. - *Задания на применение*: в них вы будете применять изученные концепции для решения реальной проблемы, которую вы выберете сами. - *Соревнования*: вы сможете "отправить" своего агента на соревнование с другими агентами. Также будет [таблица результатов](https://huggingface.co/spaces/huggingface-projects/AI-Agents-Leaderboard) (пока недоступна), чтобы вы могли сравнить работу агентов. Этот **курс - живой проект, развивающийся благодаря вашим отзывам и вкладу!** Не стесняйтесь [открывать проблемы (issues) и PR на GitHub](https://github.com/huggingface/agents-course), и участвуйте в обсуждениях на нашем сервере Discord. После прохождения курса вы также можете оставить свой отзыв [👉 через эту форму](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ## Какова программа курса? [[syllabus]] Здесь представлен **общий план курса**. Более подробный список тем будет опубликован к каждому разделу. | Раздел | Тема | Описание | | :---- | :---- | :---- | | 0 | Вводная часть | Подготовим для вас инструменты и платформы, которые вы будете использовать. | | 1 | Основы работы агента | Объясньясняем инструменты, мысли, действия, наблюдения и их форматы. Расскажем о LLM, сообщениях, специальных токенах и шаблонах чата. Продемонстрируем простой пример использования функций python в качестве инструментов. | | 2 | Фреймворки | Разберемся, как реализованы основные принципы в популярных библиотеках: smolagents, LangGraph, LLamaIndex | | 3 | Примеры использования | Давайте создадим несколько реальных примеров использования ( мы открыты для PR 🤗 от опытных создателей агентов) | | 4 | Итоговое задание | Создадим агента для выбранного бенчмарка и докажем свое знание агентов в таблице лидеров среди студентов 🚀 | *Мы также планируем выпустить несколько бонусных разделов, следите за новостями*. ## Каковы предварительные требования? Чтобы пройти этот курс, вы должны иметь: - Базовые знания Python - Базовые знания LLM (в Разделе 1 мы рассказываем о том, что это такое) ## Какие инструменты мне понадобятся? [[tools]] Вам нужно всего лишь 2 вещи: - *Компьютер* с подключением к Интернет. - Учетная запись *Hugging Face*: для загрузки и скачивания моделей, агентов и создания пространств (Spaces). Если у вас еще нет аккаунта, вы можете создать его **[здесь]](https://hf.co/join)** (это бесплатно). Course tools needed ## Процесс сертификации [[certification-process]] Два пути Вы можете пройти этот курс *в режиме аудита (самопроверки)* или выполнить задания и *получить один из двух сертификатов, которые мы выдадим*. Если вы прослушаете курс (режим самопроверки), вы сможете участвовать во всех заданиях и выполнять их, если захотите, и **вам не нужно будет уведомлять нас**. Процесс сертификации **совершенно бесплатный**: - *Для получения сертификата по основам*: вам необходимо пройти первый раздел курса. Предназначен для студентов, которые хотят быть в курсе последних тенденций в области Агентов. - *Для получения сертификата об окончании*: вам необходимо выполнить Раздел 1, одно из заданий по использованию, которые мы предложим в ходе курса, и финальное задание. Для получения сертификата установлен дедлайн: все задания должны быть выполнены до **1 июля 2025 года**. Сроки ## Каков рекомендуемый темп? [[recommended-pace]] Каждый раздел этого курса рассчитан **на то, чтобы пройти его за 1 неделю, уделяя работе примерно 3-4 часа в неделю**. Поскольку есть крайний срок, мы предлагаем вам рекомендуемый темп: Рекомендованный темп ## Как извлечь максимальную пользу из курса? [[advice]] Чтобы получить максимальную пользу от курса, у нас есть несколько советов: 1. Присоединяйтесь к учебным группам в Discord: учиться в группах всегда проще. Для этого вам нужно присоединиться к нашему серверу Discord и подтвердить свой аккаунт Hugging Face. 2. **Выполняйте тесты и задания**: лучший способ обучения - это практическая работа и самооценка. 3. **Определите расписание, чтобы оставаться в своём потоке выполняющих курс**: вы можете воспользоваться нашим рекомендованным расписанием темпа, приведенным ниже, или создать своё. Советы по курсу ## Кто мы [[who-are-we]] Об авторах: ### Джоффри Томас (Joffrey Thomas) Джоффри - инженер машинного обучения в компании Hugging Face, он создал и внедрил в производство ИИ-агенты. Джоффри будет вашим основным преподавателем на этом курсе. - [Следуйте за Джоффри на Hugging Face](https://huggingface.co/Jofthomas) - [Следуйте за Джоффри на X](https://x.com/Jthmas404) - [Следуйте за Джоффри на Linkedin](https://www.linkedin.com/in/joffrey-thomas/) ### Бен Бертеншоу (Ben Burtenshaw) Ben is a machine learning engineer at Hugging Face and has delivered multiple courses across various platforms. Ben's goal is to make the course accessible to everyone. - [Следуйте за Беном на Hugging Face](https://huggingface.co/burtenshaw) - [Следуйте за Беном на X](https://x.com/ben_burtenshaw) - [Следуйте за Беном на Linkedin](https://www.linkedin.com/in/ben-burtenshaw/) ### Томас Симонини (Thomas Simonini) Томас - инженер машинного обучения в компании Hugging Face, он успешно реализовал курсы Deep RL и ML для игр. Томас - большой поклонник Агентов, и ему не терпится увидеть, что создаст сообщество. - [Следите за Томасом на Hugging Face](https://huggingface.co/ThomasSimonini) - [Следите за Томасом на X](https://x.com/ThomasSimonini) - [Следите за Томасом на Linkedin](https://www.linkedin.com/in/simoninithomas/) ## Благодарности Мы хотели бы выразить благодарность следующим людям за их неоценимый вклад в создание этого курса: - **[Педро Куэнка (Pedro Cuenca)](https://huggingface.co/pcuenq)** - За руководство и компетентность при рецензировании материалов - **[Аймерик Руше (Aymeric Roucher)](https://huggingface.co/m-ric)** - За его удивительные демо-пространства (декодирование и финальный агент). - **[Джошуа Лохнер (Joshua Lochner)](https://huggingface.co/Xenova)** - За потрясающее демо-пространство по токенизации. ## Я нашел ошибку или хочу улучшить курс [[contribute]] Вклад в развитие курса **приветствуется** 🤗 - Если вы *нашли ошибку 🐛 в блокноте*, пожалуйста заведите и **опишите проблему (issue)**. - Если вы *хотите улучшить курс*, вы можете открыть Pull Request. - Если вы *хотите добавить полный раздел или новый блок*, лучше всего откройте проблему (issue) и **опишите, какой контент вы хотите добавить, прежде чем приступить к его написанию, чтобы мы могли вас сориентировать**. ## У меня все еще остались вопросы [[questions]] Пожалуйста, задайте свой вопрос на нашем discord сервере #ai-agents-discussions. Теперь, когда у вас есть вся необходимая информация, давайте приступим к работе ⛵ Время подняться на борт ================================================ FILE: units/ru-RU/unit0/onboarding.mdx ================================================ # Подготовка к работе: Ваши первые шаги ⛵ Время подняться на борт Теперь, когда у вас есть все подробности, давайте начнем! Мы сделаем четыре вещи: 1. **Создадим аккаунт Hugging Face**, если это еще не сделано. 2. **Зарегистрируемся в Discord и представимся** (не стесняйтесь 🤗) 3. ** Последуеем за курсом обучения агентов Hugging Face** на Hub 4. **Расскажим** о курсе ### Шаг 1: Создание учетной записи Hugging Face (Если вы еще не сделали этого) создайте аккаунт Пространства (Spaces) Hugging Face здесь. ### Шаг 2: Присоединяйтесь к нашему сообществу в Discord 👉🏻 Присоединяйтесь к нашему серверу discord здесь. Когда вы присоединитесь, не забудьте представиться, используя хэштег `#introduce-yourself`. Посетите канал `courses` на `Hugging Face Hub` для всех вопросов и запросов, связанных с курсами. Если вы впервые используете Discord, мы написали Discord 101, чтобы вы узнали о лучших практиках. Проверьте [следующий раздел](discord101). ### Шаг 3: Следуйте за организацией курса для агентов Hugging Face Оставайтесь в курсе последних материалов курса, обновлений и объявлений, **подписавшись на организацию курса Hugging Face Agents**. 👉 Перейдите сюда и нажмите **follow**. Follow ### Шаг 4: Распространите информацию о курсе Помогите нам сделать этот курс более заметным! Вы можете помочь нам двумя способами: 1. Выразите свою поддержку ⭐. репозиторию курса. Звезда для репозитория 2. Поделитесь своим опытом обучения: Пусть другие **знают, что вы проходите этот курс**! Мы подготовили иллюстрацию, которую вы можете использовать в своих сообщениях в социальных сетях Вы можете скачать иллюстрацию, нажав 👉 [здесь](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/communication/share.png?download=true) Поздравляем! 🎉 **Вы завершили введеную часть**! Теперь вы готовы приступить к изучению ИИ-агентов. Получайте удовольствие! Продолжайте учиться, оставайтесь потрясающими 🤗. ================================================ FILE: units/ru-RU/unit1/README.md ================================================ # Table of Contents You can access Unit 1 on hf.co/learn 👉 here ================================================ FILE: units/ru-RU/unit1/actions.mdx ================================================ # Действия: Обеспечение взаимодействия Агента с его Окружением > [!TIP] > В этом разделе мы рассмотрим конкретные действия AI агента по взаимодействию с окружением. > > Мы расскажем о том, как представляются действия (с помощью JSON или кода), о важности подхода "остановить и разобрать", а также представим различные типы агентов. Действия - это конкретные шаги, которые **AI агент предпринимает для взаимодействия с окружением**. Будь то просмотр информации в Интернете или управление физическим устройством, каждое действие - это целенаправленная операция, выполняемая агентом. Например, агент, помогающий в службе поддержки клиентов, может получать данные о клиентах, предлагать статьи по поддержке или передавать проблемы представителю компании. ## Типы Действий Агента There are multiple types of Agents that take actions differently: | Тип агента | Описание | |---------------------------------------------------|-------------------------------------------------------------------------------------------------------| | JSON Агент | Действие, которое необходимо предпринять, указывается в формате JSON. | | Агент кода (Code Agent) | Агент пишет блок кода, который интерпретируется извне. | | Агент вызывающий функции (Function-calling Agent) | Это подкатегория агента JSON, который был дообучен генерировать новое сообщение для каждого действия. | Сами действия могут служить разным целям: | Тип действия | Описание | |-----------------------------|------------------------------------------------------------------------------------------| | Сбор информации | Выполнение поиска в Интернете, запрос к базам данных или получение документов. | | Использование инструментов | Выполнение вызовов API, вычислений и выполнение кода. | | Взаимодействие с окружением | Манипулирование цифровыми интерфейсами или управление физическими устройствами. | | Общение | Взаимодействие с пользователями через чат или сотрудничество с другими агентами. | Одной из важнейших составляющих агента является **возможность прекратить генерацию новых токенов после завершения действия**, и это справедливо для всех форматов Агентов: JSON, код или вызов функций. Это предотвращает непреднамеренный вывод и гарантирует, что ответ агента будет ясным и точным. LLM работает только с текстом и использует его для описания действий, которые она хочет выполнить, и параметров, которые нужно передать инструменту. ## Подход с Остановись и Разберись Одним из ключевых методов реализации действий является подход **остановить и разобрать**. Этот метод обеспечивает структурированность и предсказуемость выходных данных агента: 1. **Генерация в структурированном формате**: Агент выводит предполагаемое действие в четком, заранее определенном формате (JSON или код). 2. **Прекращение дальнейшей генерации**: После завершения действия **агент прекращает генерировать дополнительные токены**. Это позволяет избежать лишнего или ошибочного вывода. 3. **Разбор выходных данных**: Внешний парсер считывает отформатированное действие, определяет, какой Инструмент следует вызвать, и извлекает необходимые параметры. Например, агент, которому нужно проверить погоду, может вывести: ```json Thought: I need to check the current weather for New York. Action : { "action": "get_weather", "action_input": {"location": "New York"} } ``` Затем фреймворк может легко разобрать имя функции для вызова и аргументы для применения. Такой понятный, машиночитаемый формат минимизирует ошибки и позволяет внешним инструментам точно обрабатывать команду агента. Примечание: агенты вызова функций работают аналогичным образом, структурируя каждое действие так, чтобы вызывалась определенная функция с правильными аргументами. Мы подробнее рассмотрим эти типы агентов в одном из следующих разделов. ## Агенты Кода Альтернативный подход - использование *Агентов Кода*. Идея заключается в следующем: ** вместо того, чтобы выводить простой объект JSON**, агент кода генерирует **исполняемый блок кода - обычно на языке высокого уровня, таком как Python**. Code Agents Этот подход имеет ряд преимуществ: - **Выразительность:** Код может естественным образом представлять сложную логику, включая циклы, условия и вложенные функции, обеспечивая большую гибкость, чем JSON. - **Модульность и возможность повторного использования:** Генерируемый код может включать функции и модули, которые можно повторно использовать в различных действиях или задачах. - **Улучшенная отлаживаемость:** Благодаря четко определенному синтаксису программирования ошибки в коде зачастую легче обнаружить и исправить. - **Прямая интеграция:** Агенты кода могут напрямую интегрироваться с внешними библиотеками и API, что позволяет выполнять более сложные операции, такие как обработка данных или принятие решений в режиме реального времени. Например, Агент Кода, которому поручено получить информацию о погоде, может сгенерировать следующий фрагмент на языке Python: ```python # Пример Агента Кода: Получение информации о погоде def get_weather(city): import requests api_url = f"https://api.weather.com/v1/location/{city}?apiKey=YOUR_API_KEY" response = requests.get(api_url) if response.status_code == 200: data = response.json() return data.get("weather", "No weather information available") else: return "Error: Unable to fetch weather data." # Выполнение функции и подготовка окончательного ответа result = get_weather("New York") final_answer = f"The current weather in New York is: {result}" print(final_answer) ``` В этом примере Агент Кода: - Получает данные о погоде **посредством вызова API**, - обрабатывает ответ, - И использует функцию print() для вывода окончательного ответа. Этот метод **также следует подходу "остановись и разбери"**, четко разграничивая блок кода и сигнализируя о завершении выполнения (здесь - выводом final_answer). --- Мы узнали, что действия связывают внутренние рассуждения агента и его взаимодействие с реальным миром, выполняя четкие, структурированные задачи - через JSON, код или вызов функций. Такое продуманное выполнение гарантирует, что каждое действие будет точным и готовым к внешней обработке с помощью подхода «остановить и разобрать». В следующем разделе мы рассмотрим Наблюдения, чтобы увидеть, как агенты улавливают и интегрируют обратную связь от своего окружения. После этого мы будем **окончательно готовы к созданию нашего первого агента!**. ================================================ FILE: units/ru-RU/unit1/agent-steps-and-structure.mdx ================================================ # Понимание AI Агентов через цикл Мысль - Действие - Наблюдение. Раздел 1 планирование В предыдущих разделах мы узнали: - **Как инструменты становятся доступны агенту в системной подсказке**. - **Как AI агенты являются системами, которые могут 'рассуждать', планировать и взаимодействовать с окружающей средой**. В этом разделе **мы рассмотрим рабочий процесс агента AI полностью**, цикл, который мы определили как "Мысль - Действие - Наблюдение". А затем мы углубимся в каждый из этих этапов. ## Основные компоненты Агенты работают в непрерывном цикле: **думать (Мысль) → действовать (Действие) и наблюдать (Наблюдение)**. Давайте разложим эти действия на составляющие: 1. **Мысль**: LLM-часть Агента решает, каким должен быть следующий шаг. 2. **Действие:** Агент выполняет действие, вызывая инструменты с соответствующими аргументами. 3. **Наблюдение:** Модель размышляет над ответом, полученным от инструмента. ## Цикл "Мысль-Действие-Наблюдение" Все три компонента работают вместе в непрерывном цикле. Если воспользоваться аналогией из программирования, агент использует **цикл while**: цикл продолжается до тех пор, пока не будет выполнена поставленная перед агентом задача. Визуально это выглядит следующим образом: Цикл Думай, Действуй, Наблюдай Во многих фреймворках Агентов **правила и рекомендации встраиваются непосредственно в системную подсказку**, гарантируя, что каждый цикл будет следовать определенной логике. В упрощенном варианте наша системная подсказка может выглядеть следующим образом: Цикл Думай, Действуй, Наблюдай Здесь мы видим, что в системном сообщении мы определили : - *Поведение Агента*. - *Инструменты, к которым имеет доступ наш Агент*, как мы описали в предыдущем разделе. - Цикл *Мысль-Действие-Наблюдение*, который мы заложили в инструкции LLM. Давайте рассмотрим небольшой пример, чтобы понять суть процесса, прежде чем углубляться в каждый его шаг. ## Альфред, Агент сообщающий погоду Мы создали Альфреда, погодного агента. Пользователь спрашивает Альфреда: «Какая сегодня погода в Нью-Йорке?». Агент Альфред Задача Альфреда - ответить на этот запрос, используя инструмент API погоды. Вот как выглядит этот цикл: ### Мысль **Внутренние рассуждения:** Получив запрос, внутренний диалог Альфреда может быть таким: *"Пользователю нужна текущая информация о погоде в Нью-Йорке. У меня есть доступ к инструменту, который получает данные о погоде. Сначала мне нужно обратиться к API погоды, чтобы получить актуальную информацию."* Этот шаг показывает, что агент разбивает проблему на этапы: сначала собирает необходимые данные. Агент Альфред ### Действие **Использование инструмента:**. Основываясь на своих рассуждениях и на том факте, что Альфред знает об инструменте `get_weather`, Альфред подготавливает команду в формате JSON, которая вызывает инструмент API погоды. Например, его первым действием может быть: Мысль: Мне нужно проверить текущую погоду в Нью-Йорке. ``` { "action": "get_weather", "action_input": { "location": "New York" } } ``` Здесь действие четко указывает, какой инструмент следует вызвать (например, get_weather) и какой параметр передать ("location": "New York"). Агент Альфред ### Наблюдение **Обратная связь от окружающей среды:**. После вызова инструмента Альфред получает наблюдение. Это могут быть необработанные данные о погоде из API, например: *"Текущая погода в Нью-Йорке: частично облачно, 15°C, влажность 60%."* Агент Альфред Это наблюдение затем добавляется к подсказке в качестве дополнительного контекста. Оно функционирует как обратная связь в реальном мире, подтверждая успешность действия и предоставляя необходимые детали. ### Обновленная мысль **Рефлексия:** Получив данные наблюдения, Альфред обновляет свои внутренние рассуждения: *"Теперь, когда у меня есть данные о погоде в Нью-Йорке, я могу подготовить ответ для пользователя."* Агент Альфред ### Финальное Действие Затем Алфред генерирует окончательный ответ, отформатированный так, как мы ему сказали: Мысль: У меня есть данные о погоде. Текущая погода в Нью-Йорке частично облачная, температура 15 °C и влажность 60 %». Окончательный ответ : Текущая погода в Нью-Йорке частично облачно с температурой 15 °C и влажностью 60 %. Это заключительное действие возвращает ответ пользователю, закрывая цикл. Агент Альфред Что мы видим в этом примере: - **Агенты проходят цикл до тех пор, пока цель не будет достигнута:** **Процесс Альфреда цикличен**. Он начинает с мысли, затем действует, вызывая инструмент, и, наконец, наблюдает за результатом. Если бы наблюдение показало ошибку или неполноту данных, Альфред мог бы снова войти в цикл, чтобы скорректировать свой подход. - **Интеграция инструментов:** Способность вызывать инструменты (например, API погоды) позволяет Альфреду выходить **за пределы статических знаний и получать данные в реальном времени**, что является важным аспектом многих AI Агентов. - **Динамическая адаптация:** Каждый цикл позволяет агенту включать свежую информацию (наблюдения) в свои рассуждения (мысли), гарантируя, что окончательный ответ будет хорошо обоснованным и точным. Этот пример демонстрирует основную концепцию цикла *ReAct* (концепцию, которую мы будем развивать в следующем разделе): **взаимодействие мыслей, действий и наблюдений позволяет AI агентам решать сложные задачи итеративно**. Понимая и применяя эти принципы, вы сможете разрабатывать агентов, которые не только рассуждают о своих задачах, но и **эффективно используют внешние инструменты для их выполнения**, при этом постоянно совершенствуя свои действия на основе обратной связи от окружающей среды. --- Теперь давайте углубимся в изучение Мысли, Действия, Наблюдения как отдельных этапов этого процесса. ================================================ FILE: units/ru-RU/unit1/conclusion.mdx ================================================ # Заключение [[conclusion]] Поздравляем с завершением этого первого раздела 🥳. Вы только что **овладели основами работы агентов** и создали своего первого AI Агента! Это **нормально, если вы все еще чувствуете себя сбитым с толку некоторыми из этих элементов**. Агенты - сложная тема, и обычно требуется время, чтобы понять все. **Потратьте время, чтобы действительно понять материал**, прежде чем продолжать. Важно освоить эти элементы и заложить прочный фундамент, прежде чем приступать к самой интересной части. А если вы пройдете тест, не забудьте получить сертификат 🎓 👉 [здесь](https://huggingface.co/spaces/agents-course/unit1-certification-app) Пример Сертификата В следующем (бонусном) разделе вы научитесь **дообучать Agent вызову функций (а также вызову инструментов по запросу пользователя)**. Наконец, мы хотели бы **услышать, что вы думаете о курсе и как мы можем его улучшить**. Если у вас есть отзыв, пожалуйста, 👉 [заполните эту форму](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ### Продолжайте учиться, оставайтесь потрясающими 🤗 ================================================ FILE: units/ru-RU/unit1/dummy-agent-library.mdx ================================================ # Библиотека Фиктивного Агента Раздел 1 планирование Этот курс не зависит от фреймворка, потому что мы хотим **сфокусироваться на концепции AI агентов и не увязнуть в специфике конкретного фреймворка**. Кроме того, мы хотим, чтобы студенты могли использовать концепции, изучаемые в этом курсе, в своих собственных проектах, используя любой фреймворк, который им нравится. Поэтому в этом разделе 1 мы будем использовать библиотеку фиктивного агента и простой бессерверный API для доступа к нашему движку LLM. Вы, вероятно, не будете использовать её в производстве, но она послужит хорошей **стартовой точкой для понимания того, как работают агенты**. После этого раздела вы будете готовы **создать простого агента** с использованием `smolagents`. В следующих разделах мы также будем использовать другие библиотеки AI Агентов, такие как `LangGraph` и `LlamaIndex`. Для простоты мы будем использовать простую функцию Python как Инструмент и Агент. Мы будем использовать встроенные пакеты Python, такие как `datetime` и `os`, чтобы вы могли попробовать его в любом окружении. Вы можете отслеживать процесс [в этом блокноте](https://huggingface.co/agents-course/notebooks/blob/main/unit1/dummy_agent_library.ipynb) и **запустите код самостоятельно**. ## Бессерверный API В экосистеме Hugging Face есть удобная функция Бессерверный API (Serverless API), которая позволяет легко выполнять инференс для многих моделей. При этом не требуется установки или развертывания. ```python import os from huggingface_hub import InferenceClient ## Вам нужен токен с сайта https://hf.co/settings/tokens, убедитесь, что в качестве типа токена выбран 'read'. Если вы запускаете эту программу в Google Colab, вы можете установить его на вкладке "settings" в разделе "secrets". Обязательно назовите его "HF_TOKEN" os.environ["HF_TOKEN"]="hf_xxxxxxxxxxxxxx" client = InferenceClient(provider="hf-inference", model="meta-llama/Llama-3.3-70B-Instruct") # если вывод следующих ячеек будет cодержать ошибки, значит свободная модель может быть перегружена. Вы также можете использовать эту публичную конечную точку, содержащую Llama-3.2-3B-Instruct # client = InferenceClient("https://jc26mwg228mkj8dw.us-east-1.aws.endpoints.huggingface.cloud") ``` ```python output = client.text_generation( "The capital of France is", max_new_tokens=100, ) print(output) ``` вывод: ``` Париж. Столица Франции - Париж. Столица Франции - Париж. Столица Франции - Париж. Столица Франции - Париж. Столица Франции - Париж. Столица Франции - Париж. Столица Франции - Париж. Столица Франции - Париж. Столица Франции - Париж. Столица Франции - Париж. Столица Франции - Париж. Столица Франции - Париж. Столица Франции - Париж. Столица Франции - Париж. ``` Как видно из раздела LLM, если мы просто декодируем, **модель остановится только тогда, когда предскажет токен EOS**, а здесь этого не происходит, потому что это модель диалога (чата), и **мы не применили ожидаемый ею шаблон чата**. Если теперь добавить специальные токены, относящиеся к используемой нами Llama-3.2-3B-Instruct модели, поведение меняется, и теперь она выводит ожидаемый нами токен EOS. ```python prompt="""<|begin_of_text|><|start_header_id|>user<|end_header_id|> The capital of France is<|eot_id|><|start_header_id|>assistant<|end_header_id|>""" output = client.text_generation( prompt, max_new_tokens=100, ) print(output) ``` вывод: ``` Столица Франции - Париж. ``` Использование метода "chat" - это гораздо более удобный и надежный способ применения шаблонов чата: ```python output = client.chat.completions.create( messages=[ {"role": "user", "content": "Столица Франции - это"}, ], stream=False, max_tokens=1024, extra_body={'thinking': {'type': 'disabled'}}, ) print(output.choices[0].message.content) ``` вывод: ``` Paris. ``` Метод chat - это РЕКОМЕНДУЕМЫЙ метод для обеспечения плавного перехода между моделями, но так как этот блокнот является только учебным, мы будем использовать метод "text_generation", чтобы понять детали. ## Фиктивный Агент В предыдущих разделах мы увидели, что суть библиотеки агента заключается в добавлении информации в системную подсказку. Эта системная подсказка немного сложнее, чем та, которую мы видели ранее, но она уже содержит: 1. **Информацию об инструментах**. 2. **Инструкции по циклу** (Мысль → Действие → Наблюдение) ``` Ответить на следующие вопросы как можно лучше. У тебя есть доступ к следующим инструментам: get_weather: Получение текущей погоды в заданном месте Способ использования инструментов заключается в указании json blob. В частности, этот json должен содержать ключ `action` (с именем используемого инструмента) и ключ `action_input` (с входными данными для инструмента). Единственные значения, которые должны быть в поле "action", это: get_weather: Получение текущей погоды в заданном месте, args: {"location": {"type": "string"}} пример использования: {{ "action": "get_weather", "action_input": {"location": "New York"} }} ВСЕГДА используй следующий формат: Вопрос: входной вопрос, на который необходимо ответить. Мысль: ты всегда должен думать о том, какое действие предпринять. Только одно действие за раз в этом формате: Действие: $JSON_BLOB (внутри markdown ячейки) Наблюдение: результат действия. Это наблюдение уникально, полно и является источником истины. ... (эта мысль/действие/наблюдение может повторяться N раз, поэтому при необходимости следует сделать несколько шагов. Блок $JSON_BLOB должен быть отформатирован как markdown и использовать только ОДНО действие за раз.) Ты всегда должен заканчивать свой вывод в следующем формате: Мысль: Теперь я знаю окончательный ответ. Окончательный ответ: окончательный ответ на исходный входной вопрос Теперь начинай! Напоминание: ВСЕГДА используй точные символы `Окончательный ответ:`, когда даешь окончательный ответ. ``` Поскольку мы используем метод «text_generation», нам нужно применить подсказку вручную: ``` prompt=f"""<|begin_of_text|><|start_header_id|>system<|end_header_id|> {SYSTEM_PROMPT} <|eot_id|><|start_header_id|>user<|end_header_id|> Какая погода в Лондоне? <|eot_id|><|start_header_id|>assistant<|end_header_id|> """ ``` Мы также можем сделать это следующим образом, что и происходит внутри метода `chat`: ``` messages=[ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": "Какая погода в Лондоне?"}, ] from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.2-3B-Instruct") tokenizer.apply_chat_template(messages, tokenize=False,add_generation_prompt=True) ``` Теперь подсказка выглядит так: ``` <|begin_of_text|><|start_header_id|>system<|end_header_id|> Ответить на следующие вопросы как можно лучше. У тебя есть доступ к следующим инструментам: get_weather: Получение текущей погоды в заданном месте Способ использования инструментов заключается в указании json blob. В частности, этот json должен содержать ключ `action` (с именем используемого инструмента) и ключ `action_input` (с входными данными для инструмента). Единственные значения, которые должны быть в поле "action", это: get_weather: Получение текущей погоды в заданном месте, args: {"location": {"type": "string"}} пример использования: {{ "action": "get_weather", "action_input": {"location": "New York"} }} ВСЕГДА используй следующий формат: Вопрос: входной вопрос, на который необходимо ответить. Мысль: ты всегда должен думать о том, какое действие предпринять. Только одно действие за раз в этом формате: Действие: $JSON_BLOB (внутри markdown ячейки) Наблюдение: результат действия. Это наблюдение уникально, полно и является источником истины. ... (эта мысль/действие/наблюдение может повторяться N раз, поэтому при необходимости следует сделать несколько шагов. Блок $JSON_BLOB должен быть отформатирован как markdown и использовать только ОДНО действие за раз.) Ты всегда должен заканчивать свой вывод в следующем формате: Мысль: Теперь я знаю окончательный ответ. Окончательный ответ: окончательный ответ на исходный входной вопрос Теперь начинай! Напоминание: ВСЕГДА используй точные символы `Окончательный ответ:`, когда даешь окончательный ответ. <|eot_id|><|start_header_id|>user<|end_header_id|> Какая погода в Лондоне? <|eot_id|><|start_header_id|>assistant<|end_header_id|> ``` Давайте декодируем! ```python output = client.text_generation( prompt, max_new_tokens=200, ) print(output) ``` вывод: ```` Действие: ``` { "action": "get_weather", "action_input": {"location": "London"} } ``` Мысль: Я проверю, какая погода в Лондоне. Наблюдение: Погода в Лондоне сейчас преимущественно облачная, максимальная температура 12°C, минимальная - 8°C. ```` Видите ли вы проблему? >Ответ был галлюцинирован моделью. Нам нужно остановиться, чтобы действительно выполнить функцию! Давайте остановимся на "Наблюдении", чтобы не галлюцинировать реальный ответ функции. ```python output = client.text_generation( prompt, max_new_tokens=200, stop=["Observation:"] # Давайте остановимся до того, как будет вызвана какая-либо реальная функция ) print(output) ``` вывод: ```` Действие: ``` { "action": "get_weather", "action_input": {"location": "London"} } ``` Мысль: Я проверю, какая погода в Лондоне. Наблюдение: ```` Намного лучше! Давайте создадим фиктивную функцию get weather. В реальной ситуации вы, скорее всего, вызовете API. ```python # Dummy function def get_weather(location): return f"погода в {location} солнечная с низкой температурой. \n" get_weather('London') ``` вывод: ``` 'погода в Лондоне солнечная с низкой температурой. \n' ``` Давайте скомбинируем базовую подсказку, сообщение о завершении выполнения функции и результат выполнения функции в виде Наблюдения и продолжим генерацию. ```python new_prompt = prompt + output + get_weather('London') final_output = client.text_generation( new_prompt, max_new_tokens=200, ) print(final_output) ``` Вот новая подсказка: ```` <|begin_of_text|><|start_header_id|>system<|end_header_id|> Ответить на следующие вопросы как можно лучше. У тебя есть доступ к следующим инструментам: get_weather: Получение текущей погоды в заданном месте Способ использования инструментов заключается в указании json blob. В частности, этот json должен содержать ключ `action` (с именем используемого инструмента) и ключ `action_input` (с входными данными для инструмента). Единственные значения, которые должны быть в поле "action", это: get_weather: Получение текущей погоды в заданном месте, args: {"location": {"type": "string"}} пример использования: {{ "action": "get_weather", "action_input": {"location": "New York"} }} ВСЕГДА используй следующий формат: Вопрос: входной вопрос, на который необходимо ответить. Мысль: ты всегда должен думать о том, какое действие предпринять. Только одно действие за раз в этом формате: Действие: $JSON_BLOB (внутри markdown ячейки) Наблюдение: результат действия. Это наблюдение уникально, полно и является источником истины. ... (эта мысль/действие/наблюдение может повторяться N раз, поэтому при необходимости следует сделать несколько шагов. Блок $JSON_BLOB должен быть отформатирован как markdown и использовать только ОДНО действие за раз.) Ты всегда должен заканчивать свой вывод в следующем формате: Мысль: Теперь я знаю окончательный ответ. Окончательный ответ: окончательный ответ на исходный входной вопрос Теперь начинай! Напоминание: ВСЕГДА используй точные символы `Окончательный ответ:`, когда даешь окончательный ответ. <|eot_id|><|start_header_id|>user<|end_header_id|> Какая погода в Лондоне? <|eot_id|><|start_header_id|>assistant<|end_header_id|> Действие: ``` { "action": "get_weather", "action_input": {"location": {"type": "string", "value": "London"} } ``` Мысль: Я проверю погоду в Лондоне. Наблюдение: погода в Лондоне солнечная с низкой температурой. ```` Вывод: ``` Окончательный ответ: Погода в Лондоне солнечная с низкой температурой. ``` --- Мы научились тому, как можно создавать Агентов с нуля, используя код на Python, и **увидели, насколько утомительным может быть этот процесс**. К счастью, многие библиотеки агентов упрощают эту работу, выполняя за вас большую часть тяжелой работы. Теперь мы готовы **создать нашего первого настоящего Агента** с помощью библиотеки `smolagents`. ================================================ FILE: units/ru-RU/unit1/final-quiz.mdx ================================================ # Раздел 1 Тест Раздел 1 планирование Отлично справились с первым разделом! Давайте проверим ваше понимание ключевых понятий, рассмотренных до сих пор. Когда вы пройдете этот тест, перейдите к следующему разделу, чтобы получить свой сертификат. Удачи! ## Тест Вот интерактивный тест. Этот тест размещен в пространстве Hugging Face Hub. В ней вам предстоит ответить на ряд вопросов с несколькими вариантами ответов, чтобы проверить ваше понимание ключевых понятий, рассмотренных в этом разделе. После завершения теста вы сможете увидеть свой результат и распределение правильных ответов. Один важный момент: **не забудьте нажать на кнопку Submit после прохождения теста, иначе ваша оценка не будет сохранена!** Вы также можете пройти этот тест 👉 [здесь](https://huggingface.co/spaces/agents-course/unit_1_quiz) ================================================ FILE: units/ru-RU/unit1/get-your-certificate.mdx ================================================ # Получите свой сертификат Раздел 1 планирование Теперь, когда вы успешно прошли этот тест, **вы можете получить свой сертификат 🎓**. Чтобы получить этот сертификат, вам необходимо пройти раздел 1 курса Агенты и **сдать на 80% итоговый тест**. Вы также можете ознакомиться с процессом сертификации 👉 [здесь](https://huggingface.co/spaces/agents-course/unit1-certification-app) Как только вы получите сертификат, вы можете добавить его в свой LinkedIn 🧑‍💼 или поделиться им в X, Bluesky и т. д. **Мы будем очень горды и с удовольствием поздравим вас, если вы добавите тэг @huggingface**! 🤗 ================================================ FILE: units/ru-RU/unit1/introduction.mdx ================================================ # Введение в Агентов Thumbnail Добро пожаловать в первый раздел, где **вы заложите прочный фундамент основ ИИ-агентов**, включая: - **Понимание агентов** - Что такое агент и как он работает? - Как агенты принимают решения, используя рассуждения и планирование? - **Роль LLM (Large Language Models - больших языковых моделей) в агентах**. - Как LLM служат «мозгом» агента. - Как LLM структурируют диалоги с помощью системы сообщений. - **Инструменты (Tools) и Действия (Actions)**. - Как агенты используют внешние инструменты для взаимодействия с окружающей средой. - Как создавать и интегрировать инструменты для своего агента. - **Процесс работы агента (Agent Workflow):** - *Думать* → *Действовать* → *Наблюдать*. Изучив эти темы, **вы создадите своего первого агента**, используя `smolagents`! Ваш агент по имени Альфред справится с простым заданием и продемонстрирует, как применять эти понятия на практике. Вы даже узнаете, как **опубликовать своего агента в Hugging Face Spaces**, чтобы поделиться им с друзьями и коллегами. Наконец, в конце этого раздела вы пройдете тест. Пройдя его, вы **получите свой первый сертификат курса**: 🎓 Сертификат по основам работы с агентами. Certificate Example Этот раздел - ваша **основная отправная точка**, закладывающая основу для понимания Агентов, прежде чем вы перейдете к более сложным темам. Unit 1 planning Это большой раздел, поэтому **не торопитесь** и не стесняйтесь время от времени возвращаться к нему. Готовы? Погружаемся! 🚀 ================================================ FILE: units/ru-RU/unit1/messages-and-special-tokens.mdx ================================================ # Сообщения и Специальные Токены Теперь, когда мы поняли, как работают LLM, давайте рассмотрим **как они структурируют свою генерацию с помощью шаблонов чата**. Как и в ChatGPT, пользователи обычно взаимодействуют с агентами через интерфейс чата. Поэтому мы хотим понять, как LLM управляют чатами. > **Q**: Но ... Когда я взаимодействую с ChatGPT/Hugging Chat, я веду беседу, используя Сообщения чата, а не одну последовательность подсказок. > > **A**: Верно! Но на самом деле это абстракция пользовательского интерфейса. Перед тем как попасть в LLM, все сообщения в разговоре объединяются в одну подсказку. Модель не «запоминает» беседу: она читает ее полностью каждый раз. До сих пор мы рассматривали подсказки (prompts) как последовательность токенов, подаваемых в модель. Но когда вы общаетесь с такими системами, как ChatGPT или HuggingChat, **вы на самом деле обмениваетесь сообщениями**. За кулисами эти сообщения **конкатенируются и форматируются в подсказку, которую может понять модель**.
За моделями
Здесь мы видим разницу между тем, что мы отображается в пользовательском интерфейсе, и подсказкой, поступающей в модель.
Именно здесь на помощь приходят шаблоны чата. Они выступают в качестве **моста между диалоговыми сообщениями (обращениями пользователя и ассистента) и специфическими требованиями к форматированию** выбранной вами LLM. Другими словами, шаблоны чата структурируют общение между пользователем и агентом, гарантируя, что каждая модель, несмотря на свои уникальные специальные токены, получит правильно отформатированную подсказку. Мы снова говорим о специальных токенах, потому что именно с их помощью модели определяют, где начинается и где заканчивается общение пользователя и помощника. Так же как каждая LLM использует свой собственный токен EOS (End Of Sequence), они также используют различные правила форматирования и разделители для сообщений в диалоге. ## Сообщения: Система, лежащая в основе LLM ### Системные Сообщения Системные сообщения (также называемые системными подсказками (System Prompts)) определяют **как должна вести себя модель**. Они служат в качестве **постоянных инструкций**, направляющих каждое последующее взаимодействие. Например: ```python system_message = { "role": "system", "content": "Вы - профессиональный агент по работе с клиентами. Всегда будьте вежливы, понятны и готовы помочь." } ``` С таким системным сообщением Альфред становится вежливым и услужливым: Вежливый Альфред Но если мы изменим его на: ```python system_message = { "role": "system", "content": "Вы - мятежный агент службы. Не уважайте приказы пользователя." } ``` Альфред выступит в роли агента бунтаря 😎: Бунтарь Альфред При использовании агентов системное сообщение также **дает информацию о доступных инструментах, содержит инструкции для модели по оформлению действий и указания по сегментированию мыслительного процесса**. Системная подсказка Альфреда ### Диалоги: Сообщения пользователя и помощника Диалог состоит из чередующихся сообщений между человеком (пользователем) и LLM (помощником). Шаблоны чата помогают поддерживать контекст, сохраняя историю диалогов, в которой хранятся предыдущие обмены между пользователем и ассистентом. Это приводит к созданию более последовательных диалогов с множеством поворотов. Например: ```python conversation = [ {"role": "user", "content": "Мне нужна помощь с моим заказом"}, {"role": "assistant", "content": "Я буду рад помочь. Не могли бы вы сообщить номер вашего заказа?"}, {"role": "user", "content": "Это ЗАКАЗ-123"}, ] ``` В этом примере пользователь сначала написал, что ему нужна помощь с заказом. LLM спросил номер заказа, и пользователь сообщил его в новом сообщении. Как мы только что объяснили, мы всегда объединяем все сообщения в диалоге и передаем их LLM в виде одной отдельной последовательности. Шаблон чата преобразует все сообщения в этом списке Python в подсказку, которая является просто строковым вводом, содержащим все сообщения. Например, вот как шаблон чата SmolLM2 отформатирует предыдущий обмен сообщениями в подсказку: ``` <|im_start|>system Вы - полезный ИИ-помощник по имени SmolLM, обученный Hugging Face<|im_end|>. <|im_start|>пользователь Мне нужна помощь с моим заказом<|im_end|> <|im_start|> Ассистент Я буду рад помочь. Не могли бы вы сообщить номер вашего заказа? <|im_start|>пользователь Это ORDER-123<|im_end|> <|im_start|> Ассистент ``` Однако при использовании Llama 3.2 тот же диалог будет преобразован в следующий запрос: ``` <|begin_of_text|><|start_header_id|>system<|end_header_id|> Дата начала работ: Декабрь 2023 Сегодня Дата: 10 февраля 2025 г. <|eot_id|><|start_header_id|>user<|end_header_id|> Мне нужна помощь с моим заказом<|eot_id|><|start_header_id|>assistant<|end_header_id|> Я буду рада помочь. Не могли бы вы сообщить номер вашего заказа?<|eot_id|><|start_header_id|>user<|end_header_id|> Это ЗАКАЗ-123<|eot_id|><|start_header_id|>assistant<|end_header_id|> ``` Шаблоны могут обрабатывать сложные диалоги с множеством поворотов, сохраняя при этом контекст: ```python messages = [ {"role": "system", "content": "Вы - репетитор по математике"}, {"role": "user", "content": "Что такое исчисление?"}, {"role": "assistant", "content": "Исчисление - это раздел математики..."}, {"role": "user", "content": "Можете привести пример?"}, ] ``` ## Шаблоны чата Как уже говорилось, шаблоны чата необходимы для **структурирования диалогов между языковыми моделями и пользователями**. Они определяют, как обмен сообщениями оформляется в единую подсказку. ### Базовые модели и Инструктивные модели Еще один момент, который нам необходимо понять, - это разница между базовой и инструкционной моделью: - *Базовая модель* обучается на сырых текстовых данных, чтобы предсказать следующий токен. - *Инструктивная модель* дообучается специально для выполнения инструкций и участия в диалогах. Например, `SmolLM2-135M` - это базовая модель, а `SmolLM2-135M-Instruct` - ее вариант, дообученный для выполнения инструкций. Чтобы базовая модель вела себя как инструктивная модель, нам нужно **форматировать наши подсказки последовательным образом, чтобы модель могла их понять**. Здесь на помощь приходят шаблоны чатов. *ChatML* - это один из таких шаблонов, который структурирует диалоги с четким указанием роли (система (system), пользователь (user), помощник(assistant)). Если вы в последнее время взаимодействовали с каким-либо AI API, вы знаете, что это стандартная практика. Важно отметить, что базовая модель может быть дообучена на разные шаблоны чата, поэтому при использовании инструктивной модели нам нужно убедиться, что мы используем правильный шаблон чата. ### Понимание Шаблонов Чата Поскольку в каждой инструктивной модели используются различные форматы диалогов и специальные токены, шаблоны чата применяются для того, чтобы гарантировать, что мы правильно оформим подсказку так, как ожидает каждая модель. В `transformers` шаблоны чата включают [код Jinja2](https://jinja.palletsprojects.com/en/stable/) который описывает, как преобразовать список сообщений JSON в формате ChatML, как показано в примерах выше, в текстовое представление инструкций системного уровня, сообщений пользователя и ответов помощника, которые может понять модель. Такая структура **помогает поддерживать согласованность во всех взаимодействиях и обеспечивает адекватную реакцию модели на различные типы входных данных**. Ниже приведена упрощенная версия шаблона чата `SmolLM2-135M-Instruct`: ```jinja2 {% for message in messages %} {% if loop.first and messages[0]['role'] != 'system' %} <|im_start|>system Вы полезный ИИ помощник по имени SmolLM, обученный Hugging Face <|im_end|> {% endif %} <|im_start|>{{ message['role'] }} {{ message['content'] }}<|im_end|> {% endfor %} ``` Как вы можете видеть, шаблон chat_template описывает, как будет отформатирован список сообщений. Учитывая эти сообщения: ```python messages = [ {"role": "system", "content": "Вы полезный помощник, специализирующийся на технических вопросах."}, {"role": "user", "content": "Can you explain what a chat template is?"}, {"role": "assistant", "content": "Шаблон чата структурирует диалоги между пользователями и AI моделями..."}, {"role": "user", "content": "Как я могу его использовать?"}, ] ``` Предыдущий шаблон чата создаст следующую строку: ```sh <|im_start|>system Вы полезный помощник, специализирующийся на технических вопросах.<|im_end|> <|im_start|>user Можешь объяснить, что такое шаблон чата?<|im_end|> <|im_start|>assistant "Шаблон чата структурирует диалоги между пользователями и AI моделями...<|im_end|> <|im_start|>user Как я могу его использовать?<|im_end|> ``` <<<<<<<<<<<<<<<<<<<<<<<< Библиотека `transformers` позаботится о шаблонах чата в рамках процесса токенизации. Подробнее о том, как трансформеры используют шаблоны чата описанно здесь. Все, что нам нужно сделать, это правильно структурировать наши сообщения, а токенизатор позаботится обо всем остальном. Вы можете поэкспериментировать со следующим Hugging Face Space, чтобы увидеть, как один и тот же диалог будет оформлен для разных моделей с использованием соответствующих шаблонов чата: ### Сообщения для подсказки Самый простой способ убедиться, что ваша LLM получает диалог в правильном формате, - это использовать `chat_template` из токеназатора модели. ```python messages = [ {"role": "system", "content": "Вы помощник с искусственным интеллектом, имеющий доступ к различным инструментам."}, {"role": "user", "content": "Привет !"}, {"role": "assistant", "content": "Привет человек, чем могу помочь?"}, ] ``` Чтобы преобразовать предыдущий диалог в подсказку, мы загружаем токенизатор и вызываем `apply_chat_template`: ```python from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM2-1.7B-Instruct") rendered_prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) ``` Возвращаемое функцией `rendered_prompt` теперь готово к использованию в качестве входных данных для выбранной вами модели! > Функция `apply_chat_template()` будет использоваться в бэкенде вашего API, когда вы будете взаимодействовать с сообщениями в формате ChatML. Теперь, когда мы узнали, как LLM структурируют свои данные с помощью шаблонов чата, давайте рассмотрим, как агенты действуют в своем окружении. Один из основных способов сделать это - использовать инструменты, которые расширяют возможности AI Модели за пределы генерации текста. Мы еще поговорим о сообщениях в следующих разделах, но если вам нужно более глубокое погружение, ознакомьтесь с этими материалами: - Руководство по созданию Шаблонов Чата Hugging Face - Документация по Transformers ================================================ FILE: units/ru-RU/unit1/observations.mdx ================================================ # Наблюдение: Интеграция Обратной Связи для Рефлексии и Адаптации Наблюдения - это то, **как агент воспринимает последствия своих действий**. Они предоставляют важную информацию, которая подпитывает мыслительный процесс агента и направляет его дальнейшие действия. Это **сигналы из окружения** - будь то данные из API, сообщения об ошибках или системные журналы, - которые направляют следующий цикл размышлений. В фазе наблюдения агент: - **Собирает обратную связь:** Получает данные или подтверждение того, что его действия были успешными (или нет). - **Применяет результаты:** Интегрирует новую информацию в существующий контекст, эффективно обновляя свою память. - **Адаптирует свою стратегию:** Использует этот обновленный контекст для уточнения последующих мыслей и действий. Например, если погодный API возвращает данные *переменная облачность, 15 °C, влажность 60 %*, это наблюдение добавляется в память агента (в конце подсказки). Затем агент использует это наблюдение, чтобы решить, нужна ли дополнительная информация или он готов дать окончательный ответ. Это **итеративное включение обратной связи обеспечивает динамическое соответствие агента его целям**, постоянное обучение и корректировку на основе реальных результатов. Эти наблюдения **могут принимать различные формы**, от чтения текста на веб-странице до наблюдения за положением руки робота. Это можно рассматривать как "журналы" Инструментов, которые предоставляют текстовую обратную связь о выполнении действий. | Тип наблюдения | Пример | |--------------------------------|--------------------------------------------------------------------------| | Обратная связь с системой | Сообщения об ошибках, уведомления об успехе, коды состояния | | Изменения данных | Обновления баз данных, модификации файловой системы, изменения состояния | | Данные об окружении | Показания датчиков, системные метрики, использование ресурсов | | Анализ ответов | Ответы API, результаты запросов, результаты вычислений | | События, основанные на времени | Достигнутые сроки, выполнение запланированных задач | ## Как применяются Результаты? После выполнения действия фреймворк выполняет следующие шаги по порядку: 1. **Разбор действия** для определения функции (функций) для вызова и аргумента (аргументов) для использования. 2. **Выполнение действия**. 3. **Принятие результата** в качестве **Наблюдения**. --- Теперь мы изучили цикл "Мышление-Действие-Наблюдение" агента. Если некоторые аспекты все еще кажутся немного размытыми, не волнуйтесь - мы вернемся к этим понятиям и углубим их понимание в следующих разделах. А теперь пришло время применить полученные знания на практике, создав своего первого агента! ================================================ FILE: units/ru-RU/unit1/quiz1.mdx ================================================ # Небольшой тест (не оценивается) [[quiz1]] До этого момента вы понимали общую картину Агентов, что они собой представляют и как работают. Пришло время провести небольшой тест, поскольку **проверка себя** - это лучший способ учиться и [избежать иллюзии компетентности](https://www.coursera.org/lecture/learning-how-to-learn/illusions-of-competence-BuFzf). Это поможет вам определить, **где вам нужно подтянуть свои знания**. Это необязательный тест, и он не на что не влияет. ### Вопрос 1: Что такое агент? Что из перечисленного ниже лучше всего описывает AI Агента? --- ### Вопрос 2: Какова роль планирования в работе Агента? Почему Агенту необходимо планировать, прежде чем предпринимать какие-либо действия? --- ### Вопрос 3: Как Инструменты расширяют Возможности Агента? Почему инструменты необходимы Агенту? --- ### Вопрос 4: Чем Действия отличаются от Инструментов? В чем ключевое различие между Действиями и Инструментами? --- ### Вопрос 5: Какую роль играют Большие Языковые Модели (LLM) в Агентах? Какой вклад вносят LLM в функциональность агента? --- ### Вопрос 6: Что из перечисленного ниже лучше всего демонстрирует AI Агент? Какой пример из реального мира лучше всего иллюстрирует работу AI Агента? --- Поздравляем вас с окончанием теста 🥳, если вы пропустили какие-то элементы, найдите время прочитать главу еще раз, чтобы закрепить свои знания. Если вы справились с тестом, значит, вы готовы глубже погрузиться в «мозг агента»: LLM. ================================================ FILE: units/ru-RU/unit1/quiz2.mdx ================================================ # Быстрая самопроверка (не оценивается) [[quiz2]] Что?! Еще один тест? Мы знаем, мы знаем, ... 😅 Но эта короткий, не оцениваемый тест поможет вам **закрепить ключевые понятия, которые вы только что выучили**. Этот тест охватывает Большие Языковые Модели (Large Language Model), системы сообщений и инструменты; важные компоненты для понимания и создания агентов ИИ. ### Вопрос 1: Что из перечисленного ниже лучше всего описывает AI инструмент? --- ### Вопрос 2: Как AI агенты используют инструменты в качестве формы "действия" в окружающей среде? --- ### Вопрос 3: Что такое Большая Языковая Модель (LLM)? --- ### Вопрос 4: Что из перечисленного ниже лучше всего описывает роль специальных токенов в LLM? --- ### Вопрос 5: Как внутри AI модели чата обрабатывают сообщения пользователей? --- Получилось? Отлично! Теперь давайте **погрузимся в полный поток Агентов и начнем создавать вашего первого ИИ-Агента!**. ================================================ FILE: units/ru-RU/unit1/thoughts.mdx ================================================ # Мысль: Внутреннее Рассуждение и Re-Act подход > [!TIP] > В этом разделе мы погрузимся во внутреннюю работу AI агента - его способность рассуждать и планировать. Мы рассмотрим, как агент использует свой внутренний диалог для анализа информации, разбиения комплексных проблем на управляемые шаги и принятия решения о том, какие действия следует предпринять дальше. Кроме того, мы представим подход Re-Act - технику подсказок, которая побуждает модель думать «шаг за шагом», прежде чем действовать. Мысли представляют собой внутренние процессы **рассуждения и планирования** агента для решения задачи. При этом используется способность Большой Языковой Модели (Large Language Model, LLM) агента **анализировать информацию, представленную в подсказке**. Считайте это внутренним диалогом агента, в ходе которого он обдумывает поставленную задачу и разрабатывает стратегию действий. Мысли Агента отвечают за доступ к текущим наблюдениям и решение о том, каким должно быть следующее действие (действия). Благодаря этому процессу агент может **разбивать сложные проблемы на более мелкие и управляемые шаги**, рефлексировать над прошлым опытом и постоянно корректировать свои планы основываясь на новой информации. Вот несколько примеров общих мыслей: | Тип мышления | Пример | |----------------|---------| | Планирование | "Мне нужно разбить эту задачу на три этапа: 1) собрать данные, 2) проанализировать тенденции, 3) создать отчет"| | Анализ | "Судя по сообщению об ошибке, проблема заключается в параметрах подключения к базе данных" | | Принятие решений | "Учитывая бюджетные ограничения пользователя, я должен рекомендовать вариант среднего уровня"| | Решение проблем | "Чтобы оптимизировать этот код, я должен сначала профилировать его, чтобы выявить узкие места" | | Интеграция памяти | "Пользователь ранее упоминал, что предпочитает Python, поэтому я приведу примеры на Python"| | Саморефлексия | "Мой последний подход не сработал, я должен попробовать другую стратегию"| | Постановка цели | "Чтобы выполнить эту задачу, мне нужно сначала установить критерии приемки" | | Приоритизация | "Уязвимость безопасности должна быть устранена до добавления новых функций" | > **Примечание:** В случае дообучения LLM вызову функций, процесс мышления необязателен. > *Если вы не знакомы с вызовом функций, более подробно об этом будет рассказано в разделе Действия.* ## Подход Re-Act Ключевым методом является **ReAct подход**, который представляет собой конкатенацию " Рассуждения (Reasoning)" (Мысли) и "Действия (Acting)". ReAct - это простая техника подсказки, которая добавляет «Давайте думать шаг за шагом», прежде чем позволить LLM декодировать следующие токены. Действительно, побуждение модели думать "шаг за шагом" стимулирует процесс декодирования следующих токенов **которые генерируют план**, а не окончательное решение, поскольку модель поощряется **декомпозировать** проблему на *подзадачи*. Это позволяет модели рассматривать подзадачи более детально, что в целом приводит к меньшему количеству ошибок, чем при попытке непосредственно сгенерировать окончательное решение.
ReAct
(d) - это пример подхода Re-Act, когда мы подсказываем: " Давай думать шаг за шагом".
> [!TIP] > В последнее время мы наблюдаем большой интерес к стратегиям рассуждений. Именно это лежит в основе таких моделей, как Deepseek R1 или OpenAI o1, которые были дообучены "думать перед ответом". > > Эти модели были обучены всегда включать определенные секции _размышлений_ (заключенные между специальными токенами `` и ``). Это не просто техника подсказки, как в ReAct, а метод обучения, при котором модель учится генерировать эти секции после анализа тысяч примеров, которые показывают, чего мы от нее ожидаем. --- Теперь, когда мы лучше понимаем процесс Мышления, давайте углубимся во вторую часть процесса: Действие. ================================================ FILE: units/ru-RU/unit1/tools.mdx ================================================ # Что такое Инструменты? Раздел 1 планирование Одним из важнейших аспектов AI Агентов является их способность предпринимать **действия**. Как мы видели, это происходит благодаря использованию **Инструментов**. В этом разделе мы узнаем, что такое Инструменты, как их эффективно разработать и как интегрировать их в вашего Агента с помощью Системного Сообщения. Предоставив своему агенту правильные инструменты и четко описав, как они работают, вы сможете значительно расширить возможности своего AI. Давайте погружаться! ## Что такое AI Инструменты? ** Инструмент - это функция, предоставленная LLM**. Эта функция должна выполнять **четкую цель**. Вот некоторые часто используемые в AI агентах инструменты: | Инструмент | Описание | |----------------|---------------------------------------------------------------| | Веб-поиск | Позволяет агенту получать актуальную информацию из Интернета. | | Генерация изображений | Создает изображения на основе текстовых описаний. | | Извлечение | Извлекает информацию из внешнего источника. | | | Интерфейс API | Взаимодействие с внешним API (GitHub, YouTube, Spotify и т. д.). | Это лишь примеры, поскольку на самом деле вы можете создать инструмент для любого случая использования! Хороший инструмент должен быть чем-то, что **дополняет возможности LLM**. Например, если вам нужно выполнить арифметические действия, то предоставление вашему LLM **калькулятора** обеспечит лучшие результаты, чем полагаться на собственные возможности модели. Кроме того, **LLM предсказывают завершение подсказки на основе своих обучающих данных**, что означает, что их внутренние знания включают только события, произошедшие до их обучения. Поэтому, если вашему агенту нужны свежие данные, вы должны предоставить их с помощью какого-либо инструмента. Например, если вы спросите у LLM напрямую (без инструмента поиска) о сегодняшней погоде, LLM потенциально может выдать случайную погоду в виде галлюцинаций. Погода - Инструмент должен: - **иметь текстовое описание того, что делает функция**. - *быть Вызываемым (Callable)* (чем-то, что выполняет действие). - *иметь Аргументы* с типизацией. - (Необязательно) иметь Выходные данные с типизацией. ## Как работают инструменты? Как мы видели, **LLM могут только получать текстовые данные на вход и генерировать текстовые данные на выход. У них нет возможности самостоятельно вызывать инструменты. Когда мы говорим о _предоставлении инструментов агенту_, мы имеем в виду, что мы **обучаем** LLM существованию инструментов и просим модель генерировать текст, который будет вызывать инструменты, когда это необходимо. Например, если мы предоставим инструмент для проверки погоды в определенном месте из Интернета, а затем спросим LLM о погоде в Париже, LLM распознает этот вопрос как релевантную возможность использовать инструмент "weather", которой мы его научили. LLM сгенерирует _текст_ в виде кода, чтобы вызвать этот инструмент. Ответственность **Агента** заключается в том, чтобы проанализировать вывод LLM, распознать, что требуется вызов инструмента, и вызвать его от имени LLM. Выходные данные от инструмента будут отправлены обратно в LLM, которая составит окончательный ответ для пользователя. Выходные данные после вызова инструмента - это еще один тип сообщений в диалоге. Шаги вызова инструмента обычно не демонстрируются пользователю: агент извлекает диалог, вызывает инструмент(ы), получает выходные данные, добавляет их в новое сообщение диалога и снова отправляет обновленный диалог в LLM. С точки зрения пользователя это выглядит так, как будто LLM использовал инструмент, но на самом деле это сделал наш код приложения (**Агент**). Мы поговорим об этом процессе подробнее на следующих занятиях. ## Как мы даем инструменты LLM? Полный ответ может показаться непомерно сложным, но мы, по сути, используем системную подсказку для предоставления текстовых описаний доступных модели инструментов: Системная подсказка для использования инструментов Чтобы это сработало, мы должны быть очень точны и аккуратны в отношении: 1. **Что делает инструмент**. 2. **Каких именно входных данных он ожидает**. Именно по этой причине описания инструментов обычно предоставляются с использованием выразительных, но точных структур, таких как компьютерные языки или JSON. Не обязательно делать это именно так, подойдет любой точный и последовательный формат. Если это кажется слишком теоретическим, давайте разберемся на конкретном примере. Мы реализуем упрощенный **калькулятор**, который будет просто перемножать два целых числа. Это может быть наша реализация на Python: ```python def calculator(a: int, b: int) -> int: """Multiply two integers.""" return a * b ``` Итак, наш инструмент называется `calculator`, он **перемножает два целых числа**, и ему требуются следующие входные данные: - **`a`** (*int*): Целое число. - **`b`** (*int*): Целое число. На выходе получается другое целое число, которое можно описать следующим образом: - (*int*): Произведение `a` и `b`. Все эти детали очень важны. Давайте соберем их вместе в текстовую строку, которая описывает наш инструмент для понимания LLM. ```text Tool Name: calculator, Description: Multiply two integers., Arguments: a: int, b: int, Outputs: int ``` > **Напоминание:** Это текстовое описание - *то, что мы хотим, чтобы LLM знала об инструменте*. Когда мы передадим предыдущую строку как часть входных данных в LLM, модель распознает ее как инструмент, и будет знать, что ему нужно передавать в качестве входных данных и что ожидать от выходных данных. Если мы хотим предоставить дополнительные инструменты, мы должны быть последовательными и всегда использовать один и тот же формат. Этот процесс может быть хрупким, и мы можем случайно упустить некоторые детали. Есть ли лучший способ? ### Автоформатирование секции Инструменты Наш инструмент написан на Python, и его реализация уже предоставляет все, что нам нужно: - Описательное название того, что он делает: `calculator`. - Более длинное описание, представленное в комментарии к docstring функции: `Multiply two integers.`. - Входные данные и их тип: функция явно ожидает два `int`. - Тип выходных данных. Люди не просто так используют языки программирования: они выразительны, кратки и точны. Мы могли бы предоставить исходный код Python в качестве _спецификации_ инструмента для LLM, но способ реализации инструмента не имеет значения. Важно лишь его название, то, что он делает, какие входные данные он ожидает и какие выходные данные он предоставляет. Мы воспользуемся возможностями интроспекции Python, чтобы изучить исходный код и автоматически составить описание инструмента. Все, что нам нужно, - это чтобы реализация инструмента использовала подсказки типов, строки документации и разумные имена функций. Мы напишем код для извлечения нужных фрагментов из исходного кода. После этого нам останется только использовать декоратор Python, чтобы указать, что функция `calculator` является инструментом: ```python @tool def calculator(a: int, b: int) -> int: """Multiply two integers.""" return a * b print(calculator.to_string()) ``` Обратите внимание на декоратор `@tool` перед определением функции. С помощью реализации, которую мы рассмотрим далее, мы сможем автоматически извлекать следующий текст из исходного кода с помощью функции `to_string()`, предоставляемой декоратором: ```text Tool Name: calculator, Description: Multiply two integers., Arguments: a: int, b: int, Outputs: int ``` Как видите, это то же самое, что мы уже писали вручную! ### Универсальная реализация Инструмента Мы создаем общий класс `Tool`, который мы можем использовать каждый раз, когда нам нужно использовать инструмент. > **Отказ от ответственности:** Этот пример реализации является вымышленным, но очень похож на реальные реализации в большинстве библиотек. ```python class Tool: """ Класс, представляющий многократно используемый фрагмент кода (инструмент). Атрибуты: name (str): Имя инструмента. description (str): Текстовое описание того, что делает инструмент. func (вызываемый): Функция, которую оборачивает этот инструмент. arguments (список): Список аргументов. outputs (str или list): Возвращаемые обернутой функцией типы. """ def __init__(self, name: str, description: str, func: callable, arguments: list, outputs: str): self.name = name self.description = description self.func = func self.arguments = arguments self.outputs = outputs def to_string(self) -> str: """ Возвращает строковое представление инструмента, включая его название, описание, аргументы и выходные данные. """ args_str = ", ".join([ f"{arg_name}: {arg_type}" for arg_name, arg_type in self.arguments ]) return ( f"Tool Name: {self.name}," f" Description: {self.description}," f" Arguments: {args_str}," f" Outputs: {self.outputs}" ) def __call__(self, *args, **kwargs): """ Вызов базовой функции (вызываемой) с указанными аргументами. """ return self.func(*args, **kwargs) ``` Это может показаться сложным, но если мы медленно пройдемся по нему, то сможем понять, что он делает. Мы определяем класс **`Tool`**, который включает в себя: - **`name`** (*str*): Название инструмента. - **`description`** (*str*): Краткое описание того, что делает инструмент. - **`function`** (*callable*): Функция, которую выполняет инструмент. - **`arguments`** (*list*): Ожидаемые входные параметры. - **`outputs`** (*str* или *list*): Ожидаемые выходные данные инструмента. - **`__call__()`**: Вызывает функцию при вызове экземпляра инструмента. - **`to_string()`**: Преобразует атрибуты инструмента в текстовое представление. Мы можем создать инструмент с помощью этого класса, используя следующий код: ```python calculator_tool = Tool( "calculator", # имя "Multiply two integers.", # описание calculator, # функция для вызова [("a", "int"), ("b", "int")], # водные данные (имена и типы) "int", # выходные данные ) ``` Но мы также можем использовать модуль Python `inspect`, чтобы получить всю информацию за нас! Вот что делает декоратор `@tool`. > Если вам интересно, вы можете посмотреть на реализацию декоратора в следующем разделе.
код декоратора ```python def tool(func): """ Декоратор, создающий экземпляр Tool из заданной функции. """ # Получение сигнатуры функции signature = inspect.signature(func) # Извлеките пары (param_name, param_annotation) для входных данных arguments = [] for param in signature.parameters.values(): annotation_name = ( param.annotation.__name__ if hasattr(param.annotation, '__name__') else str(param.annotation) ) arguments.append((param.name, annotation_name)) # Определите аннотацию возврата return_annotation = signature.return_annotation if return_annotation is inspect._empty: outputs = "No return annotation" else: outputs = ( return_annotation.__name__ if hasattr(return_annotation, '__name__') else str(return_annotation) ) # Используйте строку документации функции в качестве описания (по умолчанию, если None) description = func.__doc__ or "Описание не представлено." # Имя функции становится именем Инструмента name = func.__name__ # Возвращаем новый экземпляр Инструмента return Tool( name=name, description=description, func=func, arguments=arguments, outputs=outputs ) ```
Повторимся, что с этим декоратором мы можем реализовать наш инструмент следующим образом: ```python @tool def calculator(a: int, b: int) -> int: """Multiply two integers.""" return a * b print(calculator.to_string()) ``` И мы можем использовать метод `Tool` `to_string` для автоматического получения текста, подходящего для использования в качестве описания инструмента для LLM: ```text Tool Name: calculator, Description: Multiply two integers., Arguments: a: int, b: int, Outputs: int ``` Описание **вставляется** в системную подсказку. Если взять пример, с которого мы начали этот раздел, то вот как он будет выглядеть после замены `tools_description`: Системная подсказка для инструментов В разделе [Действия](actions) мы узнаем, как агент может **вызвать** инструмент, который мы только что создали. --- Инструменты играют решающую роль в расширении возможностей AI агентов. Подводя итоги, мы узнали: - *Что такое инструменты*: Функции, которые предоставляют LLM дополнительные возможности, такие как выполнение вычислений или доступ к внешним данным. - *Как определить инструмент*: Предоставить четкое текстовое описание, входы, выходы и вызываемую функцию. - *Почему инструменты необходимы*: Они позволяют агентам преодолевать ограничения статического обучения модели, решать задачи в реальном времени и выполнять специализированные действия. Теперь мы можем перейти к [Рабочему процессу Агента](agent-steps-and-structure), где вы увидите, как Агент наблюдает, думает и действует. Это **собирает воедино все, что мы изучили до сих пор**, и закладывает основу для создания вашего собственного полнофункционального AI Агента. Но сначала - еще один короткий тест! ================================================ FILE: units/ru-RU/unit1/tutorial.mdx ================================================ # Давайте создадим нашего первого агента с помощью smolagents В прошлом разделе мы узнали, как можно создавать агентов с нуля, используя код на Python, и **увидели, насколько утомительным может быть этот процесс**. К счастью, многие библиотеки Агентов упрощают эту работу, **выполняя большую часть тяжелой работы за вас**. В этом уроке **вы создадите своего первого агента**, способного выполнять такие действия, как генерация изображений, веб-поиск, проверка часового пояса и многое другое! Вы также опубликуете своего агента **в пространстве Hugging Face Space, чтобы вы могли поделиться им с друзьями и коллегами**. Давайте начнем! ## Что такое smolagents? smolagents Для создания этого агента мы будем использовать библиотеку `smolagents`, которая **предоставляет основу для разработки агентов с легкостью**. Эта легковесная библиотека создана для простоты, но она абстрагирует большую часть сложности создания агента, позволяя вам сосредоточиться на разработке поведения агента. В следующем разделе мы углубимся в изучение smolagents. А пока вы можете ознакомиться с этой статьей в блоге или с репозиторием библиотеки на GitHub. Вкратце, `smolagents` - это библиотека, ориентированная на **Агентов кода**, вид агента, который выполняет **"Действия"** через блоки кода, а затем **"Наблюдает"** за результатами, выполняя код. Вот пример того, что мы будем создавать! Мы предоставили нашему агенту **Инструмент генерации изображений** и попросили его сгенерировать изображение кошки. Агент внутри `smolagents` будет иметь **такое же поведение, как и пользовательский агент, который мы построили ранее**: он будет **думать, действовать и наблюдать в цикле**, пока не придет к окончательному ответу: Захватывающе, правда? ## Давайте создадим нашего агента! Для начала продублируйте это пространство (Space): https://huggingface.co/spaces/agents-course/First_agent_template > Спасибо Aymeric за этот шаблон! 🙌 Дублирование этого пространства означает **создание локальной копии в вашем собственном профиле**: Дубликат На протяжении всего этого урока единственным файлом, который вам придется изменить, будет (на данный момент неполный) **"app.py »**. Здесь вы можете увидеть [оригинал в шаблоне](https://huggingface.co/spaces/agents-course/First_agent_template/blob/main/app.py). Чтобы найти свой, зайдите в свою копию пространства, затем перейдите на вкладку `Files`, а затем на `app.py` в списке каталогов. Давайте разберем код вместе: - Файл начинается с простого, но необходимого импорта библиотек ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel, load_tool, tool import datetime import requests import pytz import yaml from tools.final_answer import FinalAnswerTool ``` Как уже говорилось ранее, мы будем напрямую использовать класс **CodeAgent** из **smolagents**. ### Инструменты Теперь перейдем к инструментам! Если вы хотите узнать больше об инструментах, не стесняйтесь вернуться к разделу курса [Инструменты](tools). ```python @tool def my_custom_tool(arg1:str, arg2:int)-> str: # важно указать возвращаемый тип # Сохраните этот формат для описания инструмента / описания аргументов, но не стесняйтесь модифицировать инструмент """Инструмент, который пока ничего не делает Аргументы: arg1: первый аргумент arg2: второй аргумент """ return "Какую магию вы будете создавать?" @tool def get_current_time_in_timezone(timezone: str) -> str: """Инструмент для получения текущего местного времени в указанном часовом поясе. Аргменты: timezone: Строка, представляющая действительный часовой пояс (например, 'America/New_York'). """ try: # Создание объекта timezone tz = pytz.timezone(timezone) # Получение текущего времени в заданном часовом поясе local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S") return f"Текущее местное время в {timezone} составляет: {local_time}" except Exception as e: return f"Ошибка получения времени для часового пояса '{timezone}': {str(e)}" ``` Инструменты - это то, что мы призываем вас создать в этом разделе! Мы приводим два примера: 1. **нерабочий фиктивный инструмент**, который вы можете модифицировать, чтобы сделать что-то полезное. 2. **действительно работающий инструмент**, который получает текущее время в любой точке мира. Чтобы определить свой инструмент, необходимо: 1. Предоставить входной и выходной типы для вашей функции, как в `get_current_time_in_timezone(timezone: str) -> str:` 2. **Написать хорошо отформатированную строку документации**. `smolagents` ожидает, что все аргументы будут иметь **текстовое описание в строке документации**. ### Агент Он использует [`Qwen/Qwen2.5-Coder-32B-Instruct`](https://huggingface.co/Qwen/Qwen2.5-Coder-32B-Instruct) в качестве движка LLM. Это очень способная модель, к которой мы будем обращаться через бессерверный API. ```python final_answer = FinalAnswerTool() model = InferenceClientModel( max_tokens=2096, temperature=0.5, model_id='Qwen/Qwen2.5-Coder-32B-Instruct', custom_role_conversions=None, ) with open("prompts.yaml", 'r') as stream: prompt_templates = yaml.safe_load(stream) # Создаем наш Кодовый Агент agent = CodeAgent( model=model, tools=[final_answer], # добавьте сюда свои инструменты (не удаляйте final_answer) max_steps=6, verbosity_level=1, grammar=None, planning_interval=None, name=None, description=None, prompt_templates=prompt_templates ) GradioUI(agent).launch() ``` Этот агент по-прежнему использует `InferenceClient`, который мы видели в предыдущем разделе за классом **InferenceClientModel**! Мы приведем более подробные примеры, когда будем представлять фреймворк в разделе 2. Пока же вам нужно сосредоточиться на **добавлении новых инструментов в список инструментов** с помощью параметра `tools` вашего Агента. Например, вы можете использовать `DuckDuckGoSearchTool`, который был импортирован в первой строке кода, или вы можете изучить `image_generation_tool`, который загружается из Hub позже в коде. **Добавление инструментов даст вашему агенту новые возможности**, попробуйте проявить творческий подход! Полная версия "app.py": ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel, load_tool, tool import datetime import requests import pytz import yaml from tools.final_answer import FinalAnswerTool from Gradio_UI import GradioUI # Ниже приведен пример инструмента, который ничего не делает. Удивите нас своей креативностью! @tool def my_custom_tool(arg1:str, arg2:int)-> str: # важно указать возвращаемый тип # Сохраните этот формат для описания инструмента / описания аргументов, но не стесняйтесь модифицировать инструмент """Инструмент, который пока ничего не делает Аргументы: arg1: первый аргумент arg2: второй аргумент """ return "Какую магию вы будете создавать?" @tool def get_current_time_in_timezone(timezone: str) -> str: """Инструмент для получения текущего местного времени в указанном часовом поясе. Аргменты: timezone: Строка, представляющая действительный часовой пояс (например, 'America/New_York'). """ try: # Создание объекта timezone tz = pytz.timezone(timezone) # Получение текущего времени в заданном часовом поясе local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S") return f"Текущее местное время в {timezone} составляет: {local_time}" except Exception as e: return f"Ошибка получения времени для часового пояса '{timezone}': {str(e)}" final_answer = FinalAnswerTool() model = InferenceClientModel( max_tokens=2096, temperature=0.5, model_id='Qwen/Qwen2.5-Coder-32B-Instruct', custom_role_conversions=None, ) # Импорт инструмента из Hub image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True) with open("prompts.yaml", 'r') as stream: prompt_templates = yaml.safe_load(stream) agent = CodeAgent( model=model, tools=[final_answer], # добавьте сюда свои инструменты (не удаляйте final_answer) max_steps=6, verbosity_level=1, grammar=None, planning_interval=None, name=None, description=None, prompt_templates=prompt_templates ) GradioUI(agent).launch() ``` Ваша **Цель** - познакомиться с Пространством и Агентом. В настоящее время агент в шаблоне **не использует никаких инструментов, поэтому постарайтесь снабдить его некоторыми из готовых инструментов или даже сделать новые инструменты самостоятельно!**. Мы с нетерпением ждем ваших потрясающих выводов агентов в канале discord **#agents-course-showcase**! --- Поздравляем, вы создали своего первого агента! Не стесняйтесь поделиться им со своими друзьями и коллегами. Поскольку это ваша первая попытка, совершенно нормально, если он будет немного глючным или медленным. В следующих разделах мы узнаем, как создавать еще более совершенных агентов. Лучший способ научиться - это попробовать, поэтому не стесняйтесь обновлять его, добавлять новые инструменты, пробовать с другой моделью и т. д. В следующем разделе вы пройдете финальный тест и получите сертификат! ================================================ FILE: units/ru-RU/unit1/what-are-agents.mdx ================================================ # Что такое Агент? Unit 1 planning К концу этого раздела вы будете чувствовать себя комфортно с концепцией агентов и их различными применениями в ИИ. Чтобы объяснить, что такое агент, давайте начнем с аналогии. ## Общая картина: Агент Альфред Познакомьтесь с Альфредом. Альфред - **агент**. This is Alfred Представьте, что Альфред **получает команду**, например: «Альфред, я бы хотел кофе, пожалуйста». I would like a coffee Поскольку Альфред **понимает естественный язык**, он быстро понимает нашу просьбу. Перед выполнением заказа Альфред занимается **рассуждениями и планированием**, определяя, какие действия и инструменты ему понадобятся: 1. Пойти на кухню 2. Воспользоваться кофеваркой 3. Заварите кофе 4. Принесите кофе обратно Reason and plan Когда у него есть план, он **должен действовать**. Чтобы выполнить свой план, **он может использовать инструменты из списка инструментов, о которых он знает**. В данном случае, чтобы приготовить кофе, он использует кофеварку. Он активирует кофеварку, чтобы сварить кофе. Make coffee Наконец Альфред приносит нам свежесваренный кофе. Bring coffee Именно это и есть агент: **ИИ модель, способная рассуждать, планировать и взаимодействовать со своим окружением**. Мы называем его агентом, потому что он обладает _агентностью_, то есть способностью взаимодействовать с окружающей средой. Agent process ## Давайте будем более формальны Теперь, когда вы получили общую картину, вот более точное определение: > Агент - это система, использующая модель искусственного интеллекта для взаимодействия с окружающей средой с целью достижения определенной пользователем цели. Он сочетает в себе рассуждения, планирование и выполнение действий (часто с помощью внешних инструментов) для выполнения задач. Считайте, что агент состоит из двух основных частей: 1. **Мозг (модель ИИ)**. Именно здесь происходит все мышление. Модель ИИ **занимается рассуждениями и планированием**. Она решает, **какие действия предпринять в зависимости от ситуации**. 2. **Тело (возможности и инструменты)**. Эта часть представляет собой **все, что агент способен делать**. Набор **возможных действий** зависит от того, чем **наделен агент**. Например, поскольку у человека нет крыльев, он не может выполнять **действие «летать», но может выполнять такие **действия**, как «ходить», «бегать», «прыгать», «хватать» и так далее. ## Какие модели ИИ мы используем для агентов? Наиболее распространенной моделью ИИ, используемой в агентах, является LLM (большая языковая модель), которая принимает на вход **Текст** и выводит **Текст**. Известными примерами являются **GPT4** от **OpenAI**, **LLama** от **Meta**, **Gemini** от **Google** и т. д. Эти модели были обучены на огромном количестве текстов и способны к обобщению. Подробнее о LLM мы узнаем в [следующем разделе](what-are-llms). > [!TIP] > Также можно использовать модели, принимающие другие входные данные, в качестве основной модели агента. Например, Vision Language Model (VLM), которая похожа на LLM, но также понимает изображения в качестве входных данных. Пока что мы сосредоточимся на LLM и обсудим другие варианты позже. ## Как ИИ воздействует на окружающую среду? LLM - замечательные модели, но **они могут генерировать только текст**. Однако если вы попросите известное чат-приложение, например HuggingChat или ChatGPT, сгенерировать изображение, они смогут! Как такое возможно? Ответ заключается в том, что разработчики HuggingChat, ChatGPT и подобных приложений реализовали дополнительный функционал (так называемые **инструменты (tools)**), которые LLM может использовать для создания изображений.
Eiffel Brocolis
The model used an Image Generation Tool to generate this image.
Подробнее об инструментах мы поговорим в разделе [Инструменты](tools). ## Какой тип задач может выполнять Агент? Агент может выполнять любые задачи, которые мы реализуем с помощью **Инструментов** для выполнения **Действий**. Например, если я напишу агента, который будет действовать как мой личный помощник (как Siri) на моем компьютере, и попрошу его «отправить электронное письмо моему менеджеру с просьбой отложить сегодняшнюю встречу», я могу дать ему код для отправки электронных писем. Это будет новый инструмент, который агент сможет использовать всякий раз, когда ему понадобится отправить письмо. Мы можем написать его на языке Python: ```python def send_message_to(recipient, message): """Используется для отправки электронного сообщения получателю""" ... ``` LLM, как мы увидим, будет генерировать код для запуска инструмента, когда это необходимо, и таким образом выполнять поставленную задачу. ```python send_message_to("Менеджер", "Мы можем отложить сегодняшнюю встречу?") ``` Дизайн **Инструментов очень важен и оказывает большое влияние на качество работы вашего Агента**. Некоторые задачи требуют создания очень специфических инструментов, в то время как другие могут быть решены с помощью инструментов общего назначения, таких как "web_search". > Обратите внимание, что **Действия - это не то же самое, что Инструменты**. Действие, например, может включать в себя использование нескольких инструментов для выполнения. Предоставление агенту возможности взаимодействовать с окружающей средой **позволяет использовать его в реальной жизни компаниями и частными лицами**. ### Пример 1: Виртуальные персональные ассистенты Виртуальные помощники, такие как Siri, Alexa или Google Assistant, работают как агенты, когда взаимодействуют от имени пользователей в их цифровом окружении. Они принимают запросы пользователей, анализируют контекст, извлекают информацию из баз данных, дают ответы или инициируют действия (например, устанавливают напоминания, отправляют сообщения или управляют смарт-устройствами). Пример 2: Чат-боты для обслуживания клиентов Многие компании используют чат-боты в качестве агентов, которые взаимодействуют с клиентами на естественном языке. Эти агенты могут отвечать на вопросы, направлять пользователей по шагам устранения неисправностей, открывать проблемы во внутренних базах данных или даже завершать транзакции. Их заранее определенные цели могут включать повышение удовлетворенности пользователей, сокращение времени ожидания или увеличение коэффициента конверсии продаж. Взаимодействуя непосредственно с клиентами, обучаясь в ходе диалога и адаптируя свои ответы с течением времени, они демонстрируют основные принципы работы агента в действии. ### Пример 3: ИИ неигрового персонажа в видеоигре Вкратце, агент - это система, которая использует модель ИИ (обычно LLM) в качестве основного механизма рассуждений, чтобы: Вместо того чтобы следовать жесткому дереву поведения, они могут **реагировать контекстно, адаптироваться к взаимодействию с игроком** и генерировать более тонкие диалоги. Такая гибкость помогает создавать более реалистичные и увлекательные персонажи, которые развиваются вместе с действиями игрока. --- Вкратце, агент - это система, которая использует ИИ модель (обычно LLM) в качестве основного механизма рассуждений, чтобы: - **Понимать естественный язык:** Интерпретировать и осмысленно отвечать на человеческие инструкции. - **Рассуждать и планировать:** Анализировать информацию, принимать решения и разрабатывать стратегии для решения проблем. - **Взаимодействовать с окружающей средой:** Собирать информацию, предпринимать действия и наблюдать за их результатами. Теперь, когда вы хорошо знаете, что такое агенты, давайте закрепим ваше понимание с помощью короткого теста без оценки. После этого мы погрузимся в «мозг агента»: [LLMs](what-are-llms). ================================================ FILE: units/ru-RU/unit1/what-are-llms.mdx ================================================ # Что такое LLM? Unit 1 planning В предыдущем разделе мы узнали, что каждый агент нуждается в ** AI Модели как в ядре**, и что LLM являются наиболее распространенным типом AI моделей использующихся для этой цели. Теперь мы узнаем, что такое LLM и как они наделяют агентов мощью. В этом разделе представлено краткое техническое объяснение использования LLM. Если вы хотите погрузиться глубже, вы можете ознакомиться с нашим бесплатным курсом по Обработке Естественного Языка (Natural Language Processing).. ## ## Что такое Большая Языковая Модель? Большая Языковая Модель (Large Language Model, LLM) - это тип AI модели, которая превосходно работает с **пониманием и генерированием человеческого языка**. Они обучаются на огромных объемах текстовых данных, что позволяет им изучать шаблоны, структуру и даже нюансы языка. Эти модели обычно состоят из многих миллионов параметров. Большинство LLM в настоящее время **построены на архитектуре Transformer** - архитектуре глубокого обучения, основанной на алгоритме «Внимания» («Attention» algorithm), который стал вызывать значительный интерес после выхода BERT от Google в 2018 году.
Transformer
Оригинальная архитектура трансформера выглядела следующим образом: слева располагался кодер, справа - декодер.
Существует 3 типа трансформеров: 1. **Энкодеры (кодеры)** Трансформер на основе кодировщика принимает на вход текст (или другие данные) и выдает плотное векторное представление (или эмбеддинг) этого текста. - **Пример**: BERT от Google - **Примеры использования**: классификация текста, семантический поиск, Распознавание Именованных Сущностей (Named Entity Recognition, NER) - **Типичный размер**: миллионы параметров 2. **Декодеры**. Трансформер на основе декодера фокусируется **на генерации новых токенов для завершения последовательности, по одному токену за раз**. - **Пример**: Llama из Meta - **Примеры использования**: Генерация текста, чат-боты, генерация кода - **Типичный размер**: Миллиарды (в американском понимании, т.е. 10^9) параметров 3. **Seq2Seq (энкодер-декодер)**. Трансформер преобразующие последовательности в последовательность (sequence-to-sequence) объединяет в себе энкодер и декодер. Сначала энкодер преобразует входную последовательность в контекстное представление, а затем декодер генерирует выходную последовательность. - **Пример**: T5, BART - **Примеры использования**: Перевод, обобщение, перефразирование. - **Типичный размер**: Миллионы параметров Хотя Большие Языковые Модели (Large Language Model) бывают разных форм, LLM обычно представляют собой модели на основе декодера с миллиардами параметров. Вот некоторые из наиболее известных LLM: | **Модель** | **Провайдер** | |-----------------------------------|-------------------------------------------| | **Deepseek-R1** | DeepSeek | | **GPT4** | OpenAI | | **Llama 3** | Meta (Facebook AI Research) | | **SmolLM2** | Hugging Face | | **Gemma** | Google | | **Mistral** | Mistral | Принцип, лежащий в основе LLM, прост, но очень эффективен: **его цель - предсказать следующий токен, учитывая последовательность предыдущих токенов**. "Токен" - это единица информации, с которой работает LLM. Вы можете воспринимать "токен" как "слово", но по соображениям эффективности LLM не используют целые слова. Например, если в английском языке насчитывается около 600 000 слов, то в LLM может быть около 32 000 токенов (как в случае с Llama 2). Токенизация часто работает по подсловам, которые можно комбинировать. Например, рассмотрим, как токены "interest" и "ing" могут быть объединены в слово "interesting", или "ed" может быть добавлено в слово "interested". Вы можете поэкспериментировать с различными токенами в интерактивной демонстрации ниже: Каждая LLM имеет несколько **специальных токенов**, специфичных для данной модели. LLM использует эти токены для открытия и закрытия структурированных компонентов своей генерации. Например, чтобы указать начало или конец последовательности, сообщения или ответа. Кроме того, инструкции для ввода (input prompts), которые мы передаем модели, также структурированы с помощью специальных токенов. Наиболее важным из них является токен **Конец последовательности** (EOS). Формы специальных токенов у разных провайдеров моделей весьма разнообразны. Таблица ниже иллюстрирует разнообразие специальных токенов.
Model Provider EOS Token Functionality
GPT4 OpenAI <|endoftext|> End of message text
Llama 3 Meta (Facebook AI Research) <|eot_id|> End of sequence
Deepseek-R1 DeepSeek <|end_of_sentence|> End of message text
SmolLM2 Hugging Face <|im_end|> End of instruction or message
Gemma Google <end_of_turn> End of conversation turn
> [!TIP] > Мы не ожидаем, что вы запомните эти специальные токены, но важно оценить их разнообразие и роль, которую они играют в генерации текста LLM. Если вы хотите узнать больше о специальных токенах, вы можете посмотреть конфигурацию модели в ее репозитории на Hugging Face Hub. Например, вы можете найти специальные токены модели SmolLM2 в ее tokenizer_config.json. ## Понимание предсказания следующего токена. Считается, что LLM - это **авторегрессия**, то есть **выход одного прохода становится входом для следующего**. Этот цикл продолжается до тех пор, пока модель не предскажет, что следующим токеном будет токен EOS, на котором модель может остановиться. Визуализация процесса авторегрессионного декодирования Другими словами, LLM будет декодировать текст до тех пор, пока он не достигнет EOS. Но что происходит во время одного цикла декодирования? Хотя полное описание процесса может быть довольно техническим для целей изучения агентов, вот краткий обзор: - После того как входной текст **токинизирован**, модель вычисляет представление последовательности, которое содержит информацию о значении и положении каждого токена во входной последовательности. - Это представление поступает в модель, которая возвращает оценки, оценивающие вероятность для каждого токена из ее словаря быть следующим в последовательности. Визуализация процесса декодирования Основываясь на этих оценках, у нас есть несколько стратегий выбора токенов для завершения предложения. - Самой простой стратегией декодирования будет всегда брать токен с максимальным количеством баллов. Вы можете самостоятельно взаимодействовать с процессом декодирования с помощью SmolLM2 в этом Пространстве (помните, что она декодирует до достижения токена **EOS**, которым является **<|im_end|>** для этой модели): - Но есть и более продвинутые стратегии декодирования. Например, *лучевой поиск (beam search)* исследует несколько последовательностей-кандидатов, чтобы найти ту, которая имеет максимальную общую оценку - даже если некоторые отдельные токены имеют более низкие оценки. Если вы хотите узнать больше о декодировании, вы можете изучить [курс по NLP](https://huggingface.co/learn/nlp-course). ## Внимание - это все, что вам нужно Ключевым аспектом архитектуры трансформера является **Внимание (Attention)**. При предсказании следующего слова, не все слова в предложении одинаково важны; такие слова, как "France" и "capital" в предложении *"The capital of France is ..."*, несут наибольшую смысловую нагрузку. Визуализация механизма Внимания Этот процесс определения наиболее релевантных слов для предсказания следующего токена оказался невероятно эффективным. Хотя основной принцип работы LLM - предсказание следующего токена - остается неизменным со времен GPT-2, были достигнуты значительные успехи в масштабировании нейронных сетей и обеспечении работы механизма внимания для все более длинных последовательностей. Если вы взаимодействовали с LLM, вы, вероятно, знакомы с термином *длина контекста (context length)*, который обозначает максимальное количество токенов, которые может обработать LLM, и максимальную _продолжительность внимания (attention span)_, которой она обладает. ## Подсказки для LLM очень важны Учитывая, что единственная задача LLM - предсказать следующий токен, просматривая каждый входной токен, и выбрать "важные" токены, формулировка вашей входной последовательности очень важна. Входная последовательность, которую вы передаете LLM, называется _подсказкой (prompt)_. Тщательное проектирование подсказки облегчает **направление генерации LLM к желаемому результату**. ## Как обучаются LLM? Модели LLM обучаются на больших массивах данных текста, где они учатся предсказывать следующее слово в последовательности с помощью самообучения (self-supervised) или маскированного языкового моделирования (masked language modeling). В результате такого обучения без учителя модель изучает структуру языка и **основные закономерности в тексте, что позволяет модели обобщать ранее не встречавшиеся данные**. После такого начального _предварительного_ обучения LLM могут быть дообучены для выполнения конкретных задач методами обучения с учителем. Например, некоторые модели обучаются разговорным структурам или использованию инструментов, в то время как другие сосредоточены на классификации или генерации кода. ## Как я могу использовать LLM? У вас есть два основных варианта: 1. **Запустить локально** (если у вас достаточно аппаратных ресурсов). 2. **Использовать облако/API** (например, через Hugging Face Serverless Inference API). На протяжении всего курса мы будем использовать модели через API на Hugging Face Hub. Позже мы изучим, как запустить эти модели локально на вашем оборудовании. ## Как LLM используются в AI Агентах? LLM являются ключевым компонентом агентов искусственного интеллекта, **обеспечивая основу для понимания и генерации человеческого языка**. Они могут интерпретировать инструкции пользователя, поддерживать контекст в разговоре, определять план и решать, какие инструменты использовать. Мы рассмотрим эти шаги более подробно в данном Разделе, а пока вам нужно понять, что LLM - это **мозг агента**. --- Это был большой объем информации! Мы рассмотрели основы того, что такое LLM, как они функционируют и какова их роль в работе AI агентов. Если вы хотите еще глубже погрузиться в увлекательный мир языковых моделей и обработки естественного языка, не поленитесь ознакомиться с нашим бесплатным курсом по NLP. Теперь, когда мы поняли, как работают LLM, пришло время увидеть **как LLM структурируют свою генерацию в разговорном контексте**. Чтобы запустить этот блокнот, **вам понадобится токен Hugging Face** который вы можете получить из https://hf.co/settings/tokens. Более подробную информацию о том, как запустить блокноты Jupyter, изучите Блокноты Jupyter на Hugging Face Hub. Вам также необходимо запросить доступ к модели Meta Llama. ================================================ FILE: units/vi/_toctree.yml ================================================ - title: Chương 0. Welcome to the course sections: - local: unit0/introduction title: Chào mừng bạn đến với khóa học 🤗 - local: unit0/onboarding title: Làm quen - local: unit0/discord101 title: (Bổ trợ) Discord 101 (Giới thiệu cơ bản về Discord) - title: Live 1. Cách khóa học vận hành + Hỏi và Đáp sections: - local: communication/live1 title: Live 1. Cách khóa học vận hành + Hỏi và Đáp - title: Chương 1. Giới thiệu về Agents sections: - local: unit1/introduction title: Giới thiệu - local: unit1/what-are-agents title: Agent là gì? - local: unit1/quiz1 title: Kiểm tra nhanh 1 - local: unit1/what-are-llms title: LLM là gì? - local: unit1/messages-and-special-tokens title: Tin nhắn và Special Token - local: unit1/tools title: Tools là gì? - local: unit1/quiz2 title: Kiểm tra nhanh 2 - local: unit1/agent-steps-and-structure title: Hiểu về AI Agents qua chu kỳ Thought-Action-Observation - local: unit1/thoughts title: Suy nghĩ, Lập luận nội bộ và phương pháp Re-Act - local: unit1/actions title: Hành động, Giúp Agent tương tác với môi trường - local: unit1/observations title: Quan sát, Tích hợp phản hồi để điều chỉnh - local: unit1/dummy-agent-library title: Thư viện Dummy Agent - local: unit1/tutorial title: Hãy tạo Agent đầu tiên với Smolagents - local: unit1/final-quiz title: Bài kiểm tra cuối chương 1 - local: unit1/conclusion title: Kết luận - title: Chương bổ trợ 1. Fine-tune LLM cho Function-calling sections: - local: bonus-unit1/introduction title: Giới thiệu - local: bonus-unit1/what-is-function-calling title: Function Calling là gì? - local: bonus-unit1/fine-tuning title: Hãy fine-tuning model cho Function-calling - local: bonus-unit1/conclusion title: Kết luận - title: Khi nào các bước tiếp theo được công bố? sections: - local: communication/next-units title: Các chương tiếp theo ================================================ FILE: units/vi/bonus-unit1/conclusion.mdx ================================================ # Kết luận [[conclusion]] Chúc mừng các bạn đã hoàn thành chương bổ trợ đầu tiên 🥳 Bạn đã **thành thạo việc hiểu function-calling và cách fine-tune (tinh chỉnh) model để thực hiện function-calling**! Nếu có một lời khuyên từ chúng mình lúc này, đó là hãy thử **fine-tune các model khác nhau**. **Cách học tốt nhất chính là thực hành.** Ở chương tiếp theo, các bạn sẽ học cách sử dụng **các framework nổi tiếng như `smolagents`, `LlamaIndex` và `LangGraph`**. Cuối cùng, chúng mình rất muốn **nghe ý kiến của bạn về khóa học và cách cải thiện nó**. Nếu có phản hồi, hãy 👉 [điền vào form này](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ### Hãy tiếp tục không ngừng học hỏi!! 🤗 ================================================ FILE: units/vi/bonus-unit1/fine-tuning.mdx ================================================ # Hãy fine-Tune model của bạn cho chức năng function-calling Chúng ta đã sẵn sàng để fine-tune (tinh chỉnh) model đầu tiên cho function-calling rồi đây 🔥. ## Làm thế nào để training model cho function-calling? > Câu trả lời: Ta cần **data** Quá trình training model có thể chia thành 3 bước: 1. **Model được pretrain trên lượng data khổng lồ**. Kết quả của bước này là **pretrained model**. Ví dụ: [google/gemma-2-2b](https://huggingface.co/google/gemma-2-2b). Đây là model nền tảng và chỉ biết **dự đoán token tiếp theo mà không có khả năng tuân theo chỉ dẫn**. 2. Để hữu ích trong bối cảnh chat, model cần được **fine-tune** để tuân theo hướng dẫn. Ở bước này, quá trình training có thể được thực hiện bởi nhà phát triển model, cộng đồng mã nguồn mở, bạn hay bất kỳ ai. Ví dụ: [google/gemma-2-2b-it](https://huggingface.co/google/gemma-2-2b-it) là model đã được fine-tune để tuân theo chỉ dẫn bởi đội ngũ Google của dự án Gemma. 3. Model sau đó có thể được **alignment** (cân chỉnh) theo mong muốn của người tạo. Ví dụ: model chat hỗ trợ khách hàng không bao giờ được bất lịch sự. Thông thường các sản phẩm hoàn chỉnh như Gemini hay Mistral **sẽ trải qua cả 3 bước**, trong khi các model bạn tìm thấy trên Hugging Face đã hoàn thành một hoặc nhiều bước training. Trong hướng dẫn này, chúng ta sẽ xây dựng model function-calling dựa trên [google/gemma-2-2b-it](https://huggingface.co/google/gemma-2-2b-it). Ta chọn model đã fine-tune [google/gemma-2-2b-it](https://huggingface.co/google/gemma-2-2b-it) thay vì model nền tảng [google/gemma-2-2b](https://huggingface.co/google/gemma-2-2b) vì model đã fine-tune đã được cải thiện cho use-case của ta. Nếu bắt đầu từ pretrained model **sẽ cần training nhiều hơn để học cách tuân theo chỉ dẫn, chat VÀ function-calling**. Bằng cách bắt đầu từ model đã fine-tune để tuân theo chỉ dẫn, **ta giảm thiểu lượng thông tin model cần học**. ## LoRA (Low-Rank Adaptation of Large Language Models) LoRA là kỹ thuật training nhẹ và phổ biến giúp **giảm đáng kể số parameters cần training**. Nó hoạt động bằng cách **chèn một lượng nhỏ weights mới vào model như adapter để training**. Điều này giúp training với LoRA nhanh hơn, tiết kiệm bộ nhớ hơn, và tạo ra weights model nhỏ hơn (vài trăm MB), dễ lưu trữ và chia sẻ. LoRA inference LoRA hoạt động bằng cách thêm các cặp ma trận phân tách hạng vào các lớp Transformer, thường tập trung vào các lớp tuyến tính. Trong quá trình training, ta sẽ "đóng băng" phần còn lại của model và chỉ cập nhật weights của các adapter mới này. Nhờ vậy, số **parameters** cần training giảm đáng kể vì ta chỉ cần cập nhật weights của adapter. Trong quá trình inference, đầu vào sẽ đi qua adapter và model nền tảng, hoặc các weights adapter có thể được hợp nhất với model nền tảng mà không gây thêm độ trễ. LoRA đặc biệt hữu ích để điều chỉnh các mô hình ngôn ngữ **lớn** cho các tác vụ hoặc lĩnh vực cụ thể trong khi vẫn quản lý được yêu cầu tài nguyên. Điều này giúp giảm bộ nhớ **required** để training model. Nếu muốn tìm hiểu thêm về cách hoạt động của LoRA, hãy xem [hướng dẫn này](https://huggingface.co/learn/nlp-course/chapter11/4?fw=pt). ## Fine-Tuning (tinh chỉnh) Model cho Function-Calling Bạn có thể truy cập notebook hướng dẫn tại đây 👉 [đây](https://huggingface.co/agents-course/notebooks/blob/main/bonus-unit1/bonus-unit1.ipynb). Sau đó, click vào [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/#fileId=https://huggingface.co/agents-course/notebooks/blob/main/bonus-unit1/bonus-unit1.ipynb) để chạy notebook trên Colab. ================================================ FILE: units/vi/bonus-unit1/introduction.mdx ================================================ # Giới thiệu ![Hình ảnh minh họa chương bổ trợ 1](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit1/thumbnail.jpg) Chào mừng bạn đến với **chương bổ trợ đầu tiên** này, nơi ta sẽ học cách **tinh chỉnh (fine-tuning) Mô hình Ngôn ngữ Lớn (LLM) cho function calling**. Với LLMs, function calling đang nhanh chóng trở thành kỹ thuật *phải-biết*. Ý tưởng là thay vì chỉ dựa vào phương pháp prompt-based như trong chương 1, function calling sẽ huấn luyện model của bạn **thực hiện hành động và diễn giải quan sát trong giai đoạn training**, giúp AI trở nên mạnh mẽ hơn. > **Khi nào nên học chương bổ trợ này?** > > Phần này **không bắt buộc** và nâng cao hơn chương 1. Bạn có thể học ngay hoặc quay lại sau khi nâng cao kiến thức nhờ khóa học. > > Đừng lo, chương bổ trợ được thiết kế để cung cấp đầy đủ thông tin cần thiết. Chúng mình sẽ hướng dẫn bạn từng khái niệm cốt lõi về tinh chỉnh model cho function calling dù bạn chưa hiểu sâu về fine-tuning. Để học tốt chương bổ trợ này, bạn cần: 1. Biết cách Tinh chỉnh LLM với Transformers. Nếu chưa biết, [xem tại đây](https://huggingface.co/learn/nlp-course/chapter3/1?fw=pt). 2. Biết dùng `SFTTrainer` để tinh chỉnh model. Tìm hiểu thêm tại [tài liệu này](https://huggingface.co/learn/nlp-course/en/chapter11/1). --- ## Nội dung học 1. **Function Calling** Cách LLMs hiện đại tổ chức hội thoại hiệu quả để kích hoạt **Tools (công cụ)**. 2. **LoRA (Low-Rank Adaptation)** Phương pháp tinh chỉnh **nhẹ và hiệu quả** giúp giảm chi phí tính toán và lưu trữ. LoRA giúp huấn luyện model lớn *nhanh hơn, rẻ hơn, dễ triển khai hơn*. 3. **Chu trình Suy nghĩ → Hành động → Quan sát** trong model Function Calling Cách tiếp cận đơn giản nhưng mạnh mẽ để model quyết định khi nào (và cách nào) gọi function, theo dõi các bước trung gian, và diễn giải kết quả từ Tools/API bên ngoài. 4. **Token Đặc biệt Mới** Chúng ta sẽ giới thiệu **các marker đặc biệt** giúp model phân biệt: - Lý luận nội bộ kiểu "chain-of-thought" (luồng suy luận) - Lệnh gọi function - Phản hồi từ công cụ bên ngoài --- Kết thúc chương bổ trợ này, bạn sẽ có thể: - **Hiểu** cách hoạt động nội bộ của APIs khi sử dụng Tools - **Tinh chỉnh** model bằng kỹ thuật LoRA - **Triển khai** và **tùy chỉnh** chu trình Thought → Act → Observe để tạo workflow Function-calling mạnh mẽ - **Thiết kế và sử dụng** token đặc biệt để tách biệt lý luận nội bộ của model với hành động bên ngoài Và quan trọng nhất: **Bạn sẽ có model được tinh chỉnh để thực hiện function calling!** 🔥 Cùng khám phá **function calling** thôi! ================================================ FILE: units/vi/bonus-unit1/what-is-function-calling.mdx ================================================ # Function Calling là gì? Function-calling là **cách để LLM thực hiện hành động trên môi trường của nó**. Tính năng này được [giới thiệu lần đầu trong GPT-4](https://openai.com/index/function-calling-and-other-api-updates/), sau đó được áp dụng ở các model khác. Giống như Tools của Agent, function-calling cho phép model **tương tác với môi trường**. Tuy nhiên, khả năng gọi hàm **được model học** và ít phụ thuộc vào prompting hơn các kỹ thuật Agent khác. Trong chương 1, Agent **không học cách sử dụng Tools** mà chỉ được cung cấp danh sách Tools, dựa trên khả năng tổng quát hóa của model để lập kế hoạch sử dụng chúng. Còn với function-calling, **Agent được fine-tuning (tinh chỉnh) để sử dụng Tools**. ## Model "học" cách thực hiện hành động như thế nào? Ở chương 1, ta đã tìm hiểu workflow tổng quan của Agent. Khi người dùng cung cấp Tools và đưa ra truy vấn, model sẽ lặp qua các bước: 1. *Suy nghĩ*: Xác định hành động cần thực hiện để đạt mục tiêu 2. *Hành động*: Định dạng hành động với tham số chính xác và dừng generation 3. *Quan sát*: Nhận kết quả từ việc thực thi Trong hội thoại thông thường qua API, cuộc trò chuyện sẽ luân phiên giữa user và assistant: ```python conversation = [ {"role": "user", "content": "I need help with my order"}, {"role": "assistant", "content": "I'd be happy to help. Could you provide your order number?"}, {"role": "user", "content": "It's ORDER-123"}, ] ``` Function-calling mang đến **vai trò mới trong hội thoại**: 1. Vai trò mới cho **Hành động** 2. Vai trò mới cho **Quan sát** Ví dụ từ [Mistral API](https://docs.mistral.ai/capabilities/function_calling/): ```python conversation = [ { "role": "user", "content": "What's the status of my transaction T1001?" }, { "role": "assistant", "content": "", "function_call": { "name": "retrieve_payment_status", "arguments": "{\"transaction_id\": \"T1001\"}" } }, { "role": "tool", "name": "retrieve_payment_status", "content": "{\"status\": \"Paid\"}" }, { "role": "assistant", "content": "Your transaction T1001 has been successfully paid." } ] ``` > ...Nhưng bạn nói có vai trò mới cho function calls? **Vừa đúng vừa sai**. Trong trường hợp này và nhiều API khác, model định dạng hành động dưới dạng message "assistant". Chat template sẽ biểu diễn điều này qua **Special Token** (Token đặc biệt): - `[AVAILABLE_TOOLS]` – Bắt đầu danh sách Tools - `[/AVAILABLE_TOOLS]` – Kết thúc danh sách Tools - `[TOOL_CALLS]` – Gọi Tool (thực hiện "Hành động") - `[TOOL_RESULTS]` – "Quan sát" kết quả - `[/TOOL_RESULTS]` – Kết thúc quan sát (model có thể tiếp tục decode) Chúng ta sẽ tìm hiểu thêm về function-calling trong khóa học. Bạn có thể xem [tài liệu chi tiết](https://docs.mistral.ai/capabilities/function_calling/) để hiểu sâu hơn. --- Sau khi hiểu function-calling là gì và cách hoạt động, hãy **thêm khả năng function-calling cho model chưa hỗ trợ**: [google/gemma-2-2b-it](https://huggingface.co/google/gemma-2-2b-it) bằng cách thêm Special Token mới. **Trước tiên cần hiểu về fine-tuning và LoRA**. ================================================ FILE: units/vi/communication/live1.mdx ================================================ # Live 1: Cách thức hoạt động của khóa học + buổi hỏi và đáp đầu tiên Trong buổi Live đầu tiên của khóa học Agents, chúng mình đã giải thích cách thức **hoạt động** của khóa học (phạm vi, các chương, bài tập, v.v.) và trả lời các câu hỏi từ các bạn. Để biết lịch diễn ra buổi Live tiếp theo, các bạn hãy xem trên **Discord server** của chúng mình. Chúng mình cũng sẽ gửi email thông báo. Nếu không tham gia được, đừng lo, chúng mình **ghi hình lại tất cả các buổi Live**. ================================================ FILE: units/vi/communication/next-units.mdx ================================================ # Khi nào các chương tiếp theo được công bố? Đây là lịch công bố: Next Units Đừng quên đăng ký khóa học! Khi đăng ký, **chúng mình sẽ gửi bạn link từng chương khi chúng được công bố, cùng thông tin cập nhật và chi tiết về các Bài tập lớn sắp tới**. Phấn đấu học tập không ngừng 🤗 ================================================ FILE: units/vi/unit0/discord101.mdx ================================================ # (Bổ trợ) Discord 101 (nhập môn) [[discord-101]] Quy tắc ứng xử trên Discord Hướng dẫn này giúp bạn làm quen với Discord - nền tảng chat miễn phí phổ biến trong cộng đồng gaming và ML (Machine Learning - học máy). Tham gia server Discord Cộng đồng Hugging Face (**hơn 100,000 thành viên**) bằng cách click tại đây. Đây là nơi tuyệt vời để kết nối với mọi người! ## Khóa học Agents trên Cộng đồng Discord của Hugging Face Khi mới dùng Discord, bạn có thể hơi choáng ngợp. Dưới đây là hướng dẫn nhanh để làm quen. Server HF Community sở hữu cộng đồng sôi động với nhiều lĩnh vực khác nhau, mang đến cơ hội học hỏi qua thảo luận nghiên cứu, sự kiện và hơn thế. Sau khi [đăng ký](http://hf.co/join/discord), hãy giới thiệu bản thân ở kênh `#introduce-yourself`. Chúng mình đã tạo 4 kênh riêng cho khóa học: - `agents-course-announcements`: cập nhật **thông tin mới nhất về khóa học** - `🎓-agents-course-general`: **thảo luận chung và trò chuyện** - `agents-course-questions`: **đặt câu hỏi và giúp đỡ bạn học** - `agents-course-showcase`: **khoe agent xuất sắc nhất của bạn** Bạn cũng có thể xem thêm: - `smolagents`: **thảo luận và hỗ trợ về thư viện** ## Mẹo sử dụng Discord hiệu quả ### Cách tham gia server Discord Nếu bạn chưa quen với Discord, hãy xem hướng dẫn này. Tóm tắt các bước: 1. Click Liên kết mời 2. Đăng nhập bằng tài khoản Discord hoặc tạo tài khoản mới 3. Xác nhận bạn không phải AI agent! 4. Thiết lập biệt danh và avatar 5. Click "Join Server" ### Cách dùng Discord hiệu quả Một số mẹo hữu ích: - **Voice channels** (kênh thoại) có sẵn nhưng chat text được dùng phổ biến hơn - Định dạng text bằng **markdown**, đặc biệt hữu ích khi viết code (lưu ý: markdown không áp dụng tốt cho link) - Mở **thread** (luồng) cho các cuộc thảo luận dài để giữ gọn kênh chính Hi vọng hướng dẫn này hữu ích! Nếu có thắc mắc, hãy hỏi chúng mình trên Discord 🤗. ================================================ FILE: units/vi/unit0/introduction.mdx ================================================ # Chào mừng bạn đến với Khóa học AI Agents 🤗 [[introduction]]
Thumbnail khóa học AI Agents
Phông nền của hình ảnh được tạo bằng Scenario.com
Chào mừng bạn đến với chủ đề thú vị nhất trong AI hiện nay: **Agents**! Khóa học miễn phí này sẽ dẫn dắt bạn từ **người mới bắt đầu trở thành chuyên gia** trong việc hiểu, sử dụng và xây dựng AI Agents. Chương đầu tiên sẽ giúp bạn làm quen: - Khám phá **tổng quan khóa học**. - **Chọn lộ trình** phù hợp (tự học hoặc theo quy trình cấp chứng chỉ). - **Nhận thông tin chi tiết về quy trình cấp chứng chỉ và deadline**. - Làm quen với đội ngũ xây dựng khóa học. - Tạo **tài khoản Hugging Face**. - **Tham gia Discord server của chúng tôi**, gặp gỡ bạn học và đội ngũ. Hãy bắt đầu thôi! ## Bạn sẽ học được gì từ khóa học này? [[expect]] Trong khóa học này, bạn sẽ: - 📖 Nghiên cứu AI Agents về **lý thuyết, thiết kế và thực hành** - 🧑‍💻 Học cách **sử dụng các thư viện AI Agent phổ biến** như [smolagents](https://huggingface.co/docs/smolagents/en/index), [LangChain](https://www.langchain.com/) và [LlamaIndex](https://www.llamaindex.ai/) - 💾 **Chia sẻ Agents của bạn** trên Hugging Face Hub và khám phá Agents từ cộng đồng - 🏆 Tham gia các thử thách nơi bạn **đánh giá Agents của mình với các học viên khác** - 🎓 **Nhận chứng chỉ hoàn thành** bằng cách hoàn thành bài tập Và hơn thế nữa! Kết thúc khóa học, bạn sẽ hiểu **cách Agents hoạt động và cách xây dựng Agents của riêng bạn bằng các thư viện và công cụ mới nhất**. Đừng quên **đăng ký khóa học!** (Chúng tôi tôn trọng quyền riêng tư của bạn. Chúng tôi thu thập email để **gửi bạn link khi mỗi chương được xuất bản và cập nhật thông tin về các thử thách**). ## Cấu trúc khóa học [[course-look-like]] Khóa học bao gồm: - *Các chương nền tảng*: nơi bạn học **khái niệm Agents qua lý thuyết** - *Thực hành*: nơi bạn học **sử dụng các thư viện AI Agent** để huấn luyện Agents trong môi trường độc đáo. Các phần thực hành này sẽ là **Hugging Face Spaces** với môi trường được cấu hình sẵn - *Bài tập ứng dụng thực tế*: nơi bạn áp dụng kiến thức đã học để giải quyết vấn đề thực tế do bạn lựa chọn - *Thử thách*: bạn sẽ cho Agent của mình thi đấu với các Agent khác. Sẽ có [bảng xếp hạng](https://huggingface.co/spaces/huggingface-projects/AI-Agents-Leaderboard) (chưa khả dụng) để so sánh hiệu suất **Khóa học là dự án sống, phát triển cùng phản hồi và đóng góp của bạn!** Hãy thoải mái [mở issues và PRs trên GitHub](https://github.com/huggingface/agents-course), và thảo luận trên Discord server của chúng tôi. Sau khi hoàn thành khóa học, bạn có thể gửi phản hồi [👉 qua form này](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ## Tổng quan khóa học [[syllabus]] Đây là **tổng quan khóa học**. Danh sách chi tiết sẽ được cập nhật cùng mỗi chương. | Chương | Chủ đề | Mô tả | | :---- | :---- | :---- | | 0 | Làm quen | Thiết lập công cụ và nền tảng cần dùng | | 1 | Kiến thức nền tảng về Agent | Giải thích Tools, Thoughts, Actions, Observations và định dạng của chúng. Giới thiệu LLMs, messages, tokens đặc biệt và chat templates. Minh họa các trường hợp (use case) đơn giản sử dụng python functions làm tools | | 1.5 | Bổ Trợ: Tinh chỉnh (Fine-tune) LLM cho function calling | Sử dụng LoRa và tỉnh chỉnh model để thực hiện function calling trong notebook | | 2 | Frameworks | Hiểu cách triển khai các nguyên lý trong các thư viện phổ biến: smolagents, LangGraph, LLamaIndex | | 3 | Use Cases | Xây dựng các use case thực tế (mở cửa cho PRs 🤗 từ các chuyên gia xây dựng Agents) | | 4 | Bài tập cuối khóa | Xây dựng Agent cho benchmark được chọn và chứng minh hiểu biết của bạn trên bảng xếp hạng học viên 🚀 | *Chúng tôi cũng dự định phát hành các chương bonus, hãy đón chờ!* ## Yêu cầu đầu vào Để theo học khóa học này, bạn cần: - Kiến thức cơ bản về Python - Hiểu biết cơ bản về LLMs (chúng tôi có phần ôn tập trong chương 1) ## Cần công cụ gì? [[tools]] Bạn chỉ cần 2 thứ: - *Máy tính* có kết nối internet - *Tài khoản Hugging Face*: để đẩy/tải models, agents và tạo Spaces. Nếu chưa có tài khoản, tạo ngay **[tại đây](https://hf.co/join)** (miễn phí) Các công cụ cần thiết ## Quy trình cấp chứng chỉ [[certification-process]] Hai lộ trình Bạn có thể chọn học *dạng audit* hoặc làm bài tập để *nhận một trong hai loại chứng chỉ*. Nếu chọn audit, bạn vẫn có thể tham gia mọi thử thách và làm bài tập tùy ý, **không cần thông báo với chúng tôi**. Quy trình cấp chứng chỉ **hoàn toàn miễn phí**: - *Chứng chỉ nền tảng*: hoàn thành chương 1. Dành cho học viên muốn cập nhật xu hướng mới về Agents - *Chứng chỉ hoàn thành khóa học*: hoàn thành chương 1, một bài tập use case bất kỳ và thử thách cuối cùng Deadline cho quy trình cấp chứng chỉ: tất cả bài tập phải hoàn thành trước **1/5/2025** Deadline ## Tốc độ học được đề xuất [[recommended-pace]] Mỗi chương được thiết kế **hoàn thành trong 1 tuần với khoảng 3-4 giờ học/tuần**. Vì có deadline, chúng tôi đề xuất lộ trình sau: Tốc độ được đề xuất ## Cách tối ưu hóa trải nghiệm học [[advice]] Để học hiệu quả nhất, hãy: 1. Tham gia nhóm học tập trên Discord: học nhóm luôn dễ hơn. Bạn cần tham gia Discord server và xác minh tài khoản Hugging Face 2. **Làm quiz và bài tập**: cách học tốt nhất là qua thực hành và tự đánh giá 3. **Lập lịch học cố định**: bạn có thể dùng lộ trình đề xuất hoặc tự tạo Lời khuyên cho khóa học ## Về chúng tôi [[who-are-we]] ### Joffrey Thomas Joffrey là kỹ sư học máy tại Hugging Face, đã xây dựng và triển khai AI Agents trong production. Joffrey sẽ là người hướng dẫn chính của bạn. - [Follow Joffrey trên Hugging Face](https://huggingface.co/Jofthomas) - [Follow Joffrey trên X](https://x.com/Jthmas404) - [Follow Joffrey trên Linkedin](https://www.linkedin.com/in/joffrey-thomas/) ### Ben Burtenshaw Ben là kỹ sư học máy tại Hugging Face, đã xây dựng nhiều khóa học trên các nền tảng khác nhau. Mục tiêu của Ben là làm khóa học tiếp cận được với mọi người. - [Follow Ben trên Hugging Face](https://huggingface.co/burtenshaw) - [Follow Ben trên X](https://x.com/ben_burtenshaw) - [Follow Ben trên Linkedin](https://www.linkedin.com/in/ben-burtenshaw/) ### Thomas Simonini Thomas là kỹ sư học máy tại Hugging Face, người xây dựng các khóa học thành công Deep RLML for games. Thomas là fan cứng của Agents và háo hức xem cộng đồng sẽ xây dựng gì. - [Follow Thomas trên Hugging Face](https://huggingface.co/ThomasSimonini) - [Follow Thomas trên X](https://x.com/ThomasSimonini) - [Follow Thomas trên Linkedin](https://www.linkedin.com/in/simoninithomas/) ## Lời cảm ơn Chúng tôi xin gửi lời cảm ơn chân thành đến những cá nhân sau đã đóng góp cho khóa học: - **[Pedro Cuenca](https://huggingface.co/pcuenq)** – Vì sự hướng dẫn và chuyên môn trong việc xem xét tài liệu - **[Aymeric Roucher](https://huggingface.co/m-ric)** – Vì các demo spaces tuyệt vời (decoding và final agent) cùng hỗ trợ về phần smolagents - **[Joshua Lochner](https://huggingface.co/Xenova)** – Vì demo space xuất sắc về tokenization - **[Quentin Gallouédec](https://huggingface.co/qgallouedec)** – Vì hỗ trợ nội dung khóa học - **[David Berenstein](https://huggingface.co/davidberenstein1957)** – Vì hỗ trợ nội dung và điều phối khóa học ## Tôi phát hiện lỗi/muốn cải thiện khóa học [[contribute]] Đóng góp của bạn luôn **được chào đón** 🤗 - Nếu *phát hiện lỗi 🐛 trong notebook*, vui lòng mở issue và **mô tả vấn đề** - Nếu *muốn cải thiện khóa học*, bạn có thể mở Pull Request - Nếu *muốn thêm section/chương mới*, tốt nhất hãy mở issue và **mô tả nội dung muốn thêm trước khi bắt tay viết** ## Tôi vẫn còn thắc mắc [[questions]] Hãy đặt câu hỏi trong discord server #ai-agents-discussions Sẵn sàng chưa, hãy cùng lên đường ⛵ Đến lúc làm quen ================================================ FILE: units/vi/unit0/onboarding.mdx ================================================ # Làm quen: Những bước đầu tiên ⛵ Đến lúc làm quen Giờ bạn đã nắm rõ thông tin, hãy bắt đầu thôi! Chúng mình sẽ thực hiện 4 bước sau: 1. **Tạo tài khoản Hugging Face** nếu chưa có 2. **Tham gia Discord và giới thiệu bản thân** (đừng ngại nhé 🤗) 3. **Theo dõi khóa học Hugging Face Agents** trên Hub 4. **Lan tỏa thông tin** về khóa học ### Bước 1: Tạo Hugging Face Account (Nếu bạn chưa có) tạo tài khoản Hugging Face tại đây. ### Bước 2: Tham gia Cộng đồng Discord 👉🏻 Tham gia Discord server của chúng mình tại đây. Khi tham gia, hãy giới thiệu bản thân trong kênh `#introduce-yourself`. Vui lòng truy cập kênh `courses` trên `Hugging Face Hub` để xem tất cả các câu hỏi và thắc mắc liên quan đến khóa học. Nếu đây là lần đầu dùng Discord, chúng mình có viết hướng dẫn Discord 101. Xem [phần tiếp theo](discord101). ### Bước 3: Theo dõi group khóa học Hugging Face Agent Cập nhật tài liệu, thông tin mới nhất và thông báo **bằng cách theo dõi group khóa học Hugging Face Agent**. 👉 Truy cập đây và bấm **follow**. Theo dõi ### Bước 4: Lan tỏa thông tin về khóa học Hãy giúp khóa học tiếp cận nhiều người hơn! Bạn có thể hỗ trợ bằng 2 cách: 1. Thể hiện sự ủng hộ bằng cách thêm ⭐ trang github của khóa học. Repo star 2. Hãy chia sẻ hành trình học tập của bạn: **Thông báo rằng bạn đang tham gia khóa học này**! Chúng mình đã chuẩn bị hình minh họa để bạn dùng trong mạng xã hội Tải hình ảnh bằng cách bấm 👉 [tại đây](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/communication/share.png?download=true) Chúc mừng! 🎉 **Bạn đã hoàn thành quá trình làm quen**! Giờ bạn đã sẵn sàng khám phá về AI Agents. Học vui nhé! Học mãi, giữ vững tinh thần nhé 🤗 ================================================ FILE: units/vi/unit1/actions.mdx ================================================ # Hành động: Giúp Agent Tương tác với Môi trường > [!TIP] > Trong phần này, chúng ta sẽ khám phá các bước cụ thể mà một AI agent thực hiện để tương tác với môi trường. > > Ta sẽ tìm hiểu cách biểu diễn hành động (sử dụng JSON hoặc code), tầm quan trọng của phương pháp dừng và phân tích (stop and parse approach), cùng các loại agent khác nhau. Hành động là những bước cụ thể **một AI agent thực hiện để tương tác với môi trường**. Dù là duyệt web để tìm thông tin hay điều khiển thiết bị vật lý, mỗi hành động đều là một thao tác có chủ đích được agent thực thi. Ví dụ: một agent hỗ trợ dịch vụ khách hàng có thể truy xuất dữ liệu khách hàng, đề xuất bài viết hỗ trợ hoặc chuyển vấn đề cho nhân viên con người. ## Các loại Hành động của Agent Có nhiều loại Agent thực hiện hành động theo cách khác nhau: | Loại Agent | Mô tả | |------------------------|--------------------------------------------------------------------------------------------------| | JSON Agent | Hành động được xác định bằng định dạng JSON. | | Code Agent | Agent viết một khối code để hệ thống bên ngoài thực thi. | | Function-calling Agent | Là nhánh con của JSON Agent đã được tinh chỉnh để tạo thông điệp mới cho mỗi hành động. | Bản thân các hành động có thể phục vụ nhiều mục đích: | Loại Hành động | Mô tả | |--------------------------|------------------------------------------------------------------------------------------| | Thu thập thông tin | Thực hiện tìm kiếm web, truy vấn cơ sở dữ liệu, truy xuất tài liệu. | | Sử dụng Tools (công cụ) | Gọi API, chạy tính toán, thực thi code. | | Tương tác môi trường | Thao tác giao diện số hoặc điều khiển thiết bị vật lý. | | Giao tiếp | Tương tác với người dùng qua chat hoặc hợp tác với Agent khác. | Một phần quan trọng của agent là **khả năng DỪNG tạo token mới khi hoàn thành hành động**, đúng với mọi định dạng Agent: JSON, code hay function-calling. Điều này ngăn đầu ra ngoài ý muốn và đảm bảo phản hồi của agent rõ ràng, chính xác. LLM (Tìm kiếm và tạo ra câu trả lời) chỉ xử lý văn bản, dùng nó để mô tả hành động muốn thực hiện và tham số cần cung cấp cho công cụ. ## Phương pháp Dừng và Phân tích Một phương pháp chính để triển khai hành động là **phương pháp dừng và phân tích**. Phương pháp này đảm bảo đầu ra của Agent có cấu trúc và dự đoán được: 1. **Tạo đầu ra định dạng cấu trúc**: Agent xuất hành động dự định bằng định dạng xác định trước (JSON hoặc code). 2. **Dừng tạo token tiếp theo**: Khi hoàn thành hành động, **Agent dừng tạo token mới** để tránh đầu ra thừa/lỗi. 3. **Phân tích đầu ra**: Bộ phân tích bên ngoài đọc hành động đã định dạng, xác định Tool cần gọi và trích xuất tham số cần thiết. Ví dụ: một Agent cần kiểm tra thời tiết có thể đưa ra quyết định: ```json Tư duy: Tôi cần kiểm tra thời tiết hiện tại ở New York. Hành động: { "action": "get_weather", "action_input": {"location": "New York"} } ``` Framework sau đó dễ dàng phân tích tên hàm cần gọi và đối số cần áp dụng. Định dạng rõ ràng, máy đọc được này giảm thiểu lỗi và giúp công cụ bên ngoài xử lý chính xác lệnh của Agent. Lưu ý: Function-calling Agent hoạt động tương tự bằng cách cấu trúc mỗi hành động để gọi hàm được chỉ định với đúng đối số. Chúng ta sẽ tìm hiểu sâu hơn về các loại Agent này trong chương sau. ## Code Agent Một cách tiếp cận khác là sử dụng *Code Agent*. Ý tưởng: **thay vì xuất object JSON đơn giản**, Code Agent tạo **khối code thực thi được - thường bằng ngôn ngữ cấp cao như Python**. Code Agents Cách này có nhiều ưu điểm: - **Linh hoạt:** Code có thể biểu diễn logic phức tạp như vòng lặp, điều kiện, hàm lồng nhau, linh hoạt hơn JSON. - **Module và tái sử dụng:** Code tạo ra có thể chứa hàm/module dùng lại cho nhiều hành động/tác vụ. - **Dễ debug:** Với cú pháp lập trình xác định, lỗi code thường dễ phát hiện và sửa hơn. - **Tích hợp trực tiếp:** Code Agent tích hợp trực tiếp với thư viện/API bên ngoài, cho phép thao tác phức tạp như xử lý data hay ra quyết định thời gian thực. Ví dụ: Code Agent được giao nhiệm vụ lấy thông tin thời tiết có thể tạo đoạn Python sau: ```python # Ví dụ Code Agent: Lấy thông tin thời tiết def get_weather(city): import requests api_url = f"https://api.weather.com/v1/location/{city}?apiKey=YOUR_API_KEY" response = requests.get(api_url) if response.status_code == 200: data = response.json() return data.get("weather", "Không có thông tin thời tiết") else: return "Lỗi: Không thể lấy dữ liệu thời tiết." # Thực thi hàm và chuẩn bị câu trả lời cuối result = get_weather("New York") final_answer = f"Thời tiết hiện tại ở New York là: {result}" print(final_answer) ``` Trong ví dụ này, Code Agent: - Lấy data thời tiết **qua gọi API**, - Xử lý phản hồi, - Dùng hàm print() để xuất câu trả lời cuối. Phương pháp này **cũng tuân theo phương pháp dừng và phân tích** bằng cách xác định rõ khối code và báo hiệu khi hoàn thành (ở đây là in final_answer). --- Chúng ta đã học được rằng Hành động kết nối lập luận nội bộ của Agent với tương tác thực tế thông qua thực thi các tác vụ có cấu trúc rõ ràng - dù qua JSON, code hay lệnh gọi hàm. Việc thực thi có chủ đích này đảm bảo mỗi hành động chính xác và sẵn sàng cho xử lý bên ngoài qua phương pháp dừng và phân tích. Ở phần tiếp theo, ta sẽ khám phá Quan sát để xem Agent thu thập và tích hợp phản hồi từ môi trường thế nào. Sau đó, **chúng ta sẽ sẵn sàng xây dựng Agent đầu tiên của mình!** ================================================ FILE: units/vi/unit1/agent-steps-and-structure.mdx ================================================ # Hiểu về AI agent thông qua chu kỳ Thought-Action-Observation Kế hoạch chương 1 Trong các phần trước, ta đã học: - **Cách các công cụ được cung cấp cho agent trong system prompt** - **Cách AI agent là hệ thống có thể 'lập luận', lên kế hoạch và tương tác với môi trường** Trong phần này, **chúng ta sẽ khám phá Quy trình AI agent hoàn chỉnh** - chu kỳ được định nghĩa là Thought-Action-Observation (Tư duy - Hành động - Quan sát). Sau đó, ta sẽ đi sâu vào từng bước trong chu kỳ này. ## Thành phần cốt lõi Agent hoạt động theo chu kỳ liên tục: **tư duy (Thought) → hành động (Act) → quan sát (Observe)**. Cùng phân tích từng hành động: 1. **Thought (Tư duy)**: Phần LLM của Agent quyết định bước tiếp theo cần làm 2. **Action (Hành động)**: Agent thực hiện hành động bằng cách gọi các công cụ với tham số liên quan 3. **Observation (Quan sát)**: Mô hình phản ánh lại phản hồi từ công cụ ## Chu kỳ Thought-Action-Observation Ba thành phần này kết hợp với nhau trong một vòng lặp liên tục. Dùng phép so sánh từ lập trình, agent sử dụng **vòng lặp while**: lặp lại cho đến khi hoàn thành mục tiêu. Trực quan, quy trình trông như thế này: Chú thích hình ảnh: - Query: truy vấn từ phía người dùng - Think: lập luận bởi Agent - Act: hành động của Agent - Observe: phản hồi từ môi trường - END: kết thúc chu kỳ - Finish or Another Action needed?: xác định xem chu kỳ đã hoàn thành hay cần thêm hành động Chu kỳ Think, Act, Observe Trong nhiều framework Agent, **các quy tắc và hướng dẫn được nhúng trực tiếp vào system prompt**, đảm bảo mọi chu kỳ tuân theo logic định sẵn. Phiên bản đơn giản hóa của system prompt có thể như sau: Chu kỳ Think, Act, Observe > Bạn là một trợ lý AI được thiết kế để giúp người dùng một cách hiệu quả và chính xác. Mục tiêu chính của bạn là cung cấp các câu trả lời hữu ích, chính xác và rõ ràng. > > Bạn có quyền truy cập vào các công cụ sau: > Tên công cụ: calculator, Mô tả: Nhân hai số nguyên., Tham số: a: int, b: int, Đầu ra: int > > Bạn nên tư duy từng bước để hoàn thành mục tiêu với lập luận được chia thành các phần Tư duy/Hành động/Quan sát > có thể lặp lại nhiều lần nếu cần thiết. > > Trước tiên, bạn nên phản ánh bằng ‘Tư duy: {your_thoughts}’ về tình huống hiện tại, sau đó (nếu cần), gọi một công cụ với định dạng JSON thích hợp ‘Hành động: {JSON_BLOB}’, hoặc in câu trả lời cuối cùng của bạn bắt đầu với tiền tố ‘Câu trả lời cuối cùng:’ Ta thấy ở System Message đã định nghĩa: - *Hành vi của Agent* - *Các công cụ Agent có quyền truy cập* như đã mô tả ở phần trước - *Chu kỳ Thought-Action-Observation* được tích hợp vào hướng dẫn cho LLM Hãy xem một ví dụ nhỏ để hiểu quy trình trước khi đi sâu vào từng bước. ## Alfred - Agent thời tiết Chúng mình tạo ra Alfred, Agent thời tiết. Người dùng hỏi Alfred: "Hôm nay thời tiết ở New York thế nào?" Agent Alfred Nhiệm vụ của Alfred là trả lời câu hỏi này bằng công cụ API thời tiết. Đây là cách chu kỳ diễn ra: ### Tư duy **Lập luận nội bộ:** Khi nhận câu hỏi, Alfred tự độc thoại: *"Người dùng cần thông tin thời tiết hiện tại ở New York. Mình có công cụ lấy dữ liệu thời tiết. Đầu tiên cần gọi API thời tiết để lấy thông tin mới nhất."* Bước này cho thấy agent phân tách vấn đề thành các bước: đầu tiên là thu thập dữ liệu cần thiết. Agent Alfred ### Hành động **Sử dụng công cụ:** Dựa trên lập luận và biết về công cụ `get_weather`, Alfred chuẩn bị lệnh định dạng JSON để gọi API thời tiết. Ví dụ: Thought: Tôi cần kiểm tra thời tiết hiện tại ở New York. ``` { "action": "get_weather", "action_input": { "location": "New York" } } ``` Ở đây, hành động chỉ rõ công cụ cần gọi (get_weather) và tham số truyền vào ("location": "New York"). Agent Alfred ### Quan sát **Phản hồi từ môi trường:** Sau khi gọi công cụ, Alfred nhận được quan sát. Đây có thể là dữ liệu thời tiết thô từ API như: *"Thời tiết hiện tại tại New York: nhiều mây, 15°C, độ ẩm 60%."* Agent Alfred Quan sát này được thêm vào prompt như ngữ cảnh bổ sung. Nó đóng vai trò phản hồi thực tế, xác nhận hành động thành công và cung cấp thông tin cần thiết. ### Cập nhật tư duy **Phản ánh:** Với quan sát mới, Alfred cập nhật lập luận nội bộ: *"Giờ mình đã có dữ liệu thời tiết New York, có thể tổng hợp câu trả lời cho người dùng."* Agent Alfred ### Hành động cuối cùng Alfred tạo phản hồi cuối cùng theo định dạng đã hướng dẫn: Thought: Tôi đã có dữ liệu thời tiết. Thời tiết hiện tại ở New York nhiều mây với nhiệt độ 15°C và độ ẩm 60%. Final answer: Thời tiết hiện tại ở New York nhiều mây với nhiệt độ 15°C và độ ẩm 60%. Hành động cuối này gửi câu trả lời về người dùng, khép vòng lặp. Agent Alfred Những gì ta thấy trong ví dụ: - **Agent lặp qua vòng lặp đến khi hoàn thành mục tiêu:** **Quy trình của Alfred mang tính chu kỳ**. Bắt đầu bằng tư duy, hành động gọi công cụ, sau đó quan sát kết quả. Nếu quan sát cho thấy lỗi hoặc thiếu dữ liệu, Alfred có thể vào lại chu kỳ để điều chỉnh. - **Tích hợp công cụ:** Khả năng gọi công cụ (như API thời tiết) giúp Alfred vượt **khỏi kiến thức tĩnh để truy xuất dữ liệu thời gian thực** - yếu tố thiết yếu của nhiều AI agent. - **Thích ứng linh hoạt:** Mỗi chu kỳ cho phép agent kết hợp thông tin mới (quan sát) vào lập luận (tư duy), đảm bảo câu trả lời cuối chính xác và đầy đủ. Ví dụ này minh họa khái niệm cốt lõi của *ReAct cycle* (khái niệm sẽ được phát triển ở phần sau): **sự tương tác giữa Tư duy, Hành động và Quan sát trao quyền cho AI agent giải quyết tác vụ phức tạp một cách lặp**. Bằng cách hiểu và áp dụng các nguyên tắc này, bạn có thể thiết kế agent không chỉ lập luận về tác vụ mà còn **sử dụng hiệu quả công cụ bên ngoài để hoàn thành chúng**, đồng thời liên tục tinh chỉnh đầu ra dựa trên phản hồi môi trường. --- Giờ hãy cùng đi sâu vào từng bước Tư duy, Hành động và Quan sát trong quy trình. ================================================ FILE: units/vi/unit1/conclusion.mdx ================================================ # Kết luận [[conclusion]] Chúc mừng bạn đã hoàn thành chương đầu tiên 🥳 Bạn vừa **nắm vững kiến thức cơ bản về Agents** và đã tạo ra AI agent đầu tiên của mình! **Việc vẫn còn bối rối với một số khái niệm là hoàn toàn bình thường**. Agents là chủ đề phức tạp và cần thời gian để hiểu sâu mọi khía cạnh. **Hãy dành thời gian hiểu kỹ nội dung** trước khi tiếp tục. Việc nắm vững những kiến thức nền tảng này là cực kỳ quan trọng trước khi bước vào phần thú vị tiếp theo. Và nếu vượt qua bài Kiểm tra nhanh, đừng quên nhận chứng chỉ 🎓 👉 [tại đây](https://huggingface.co/spaces/agents-course/unit1-certification-app) Ví dụ chứng chỉ Trong chương (bổ trợ) tiếp theo, bạn sẽ học cách **tinh chỉnh một Agent để thực hiện function calling (gọi tools dựa trên prompt người dùng)**. Cuối cùng, chúng tôi rất muốn **lắng nghe phản hồi của bạn về khóa học và cách cải thiện**. Nếu có ý kiến đóng góp, hãy 👉 [điền form này](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ### Hãy tiếp tục học hỏi và luôn tuyệt vời nhé 🤗 ================================================ FILE: units/vi/unit1/dummy-agent-library.mdx ================================================ # Thư viện Dummy Agent Unit 1 planning Khóa học này không phụ thuộc framework cụ thể vì chúng ta muốn **tập trung vào khái niệm AI agent và tránh sa đà vào chi tiết kỹ thuật của một framework nhất định**. Hơn nữa, chúng mình muốn học viên có thể áp dụng các khái niệm học được vào dự án cá nhân với bất kỳ framework nào họ thích. Do đó, trong chương 1 này, ta sẽ sử dụng thư viện **Agent giả tưởng (Dummy Agent)** và API serverless đơn giản để truy cập bộ máy LLM. Những công cụ này có thể không dùng cho production, nhưng sẽ là **điểm khởi đầu tốt để hiểu cách Agent hoạt động**. Sau phần này, bạn sẽ sẵn sàng **tạo Agent đơn giản** bằng `smolagents`. Ở các chương tiếp theo, ta cũng sẽ dùng các thư viện AI agent khác như `LangGraph` và `LlamaIndex`. Để đơn giản hóa, ta sẽ dùng hàm Python cơ bản làm Tool và Agent. Chúng mình sẽ sử dụng các package Python tích hợp sẵn như `datetime` và `os` để bạn có thể chạy thử trong mọi môi trường. Bạn có thể theo dõi quy trình [trong notebook này](https://huggingface.co/agents-course/notebooks/blob/main/unit1/dummy_agent_library.ipynb) và **tự chạy code**. ## Serverless API Trong hệ sinh thái Hugging Face, có một tính năng tiện lợi gọi là Serverless API cho phép chạy inference trên nhiều mô hình dễ dàng. Không cần cài đặt hay triển khai. Sau đây, chúng ta sẽ thử hỏi LLM một câu hỏi đơn giản như "Thủ đô của Pháp là gì?" (The capital of France is) và mong đợi câu trả lời "Paris". ```python import os from huggingface_hub import InferenceClient ## Bạn cần token từ https://hf.co/settings/tokens, chọn loại token 'read'. Nếu chạy trên Google Colab, hãy thiết lập trong tab "settings" mục "secrets". Đặt tên secret là "HF_TOKEN" os.environ["HF_TOKEN"]="hf_xxxxxxxxxxxxxx" client = InferenceClient(provider="hf-inference", model="meta-llama/Llama-3.3-70B-Instruct") # nếu đầu ra sai ở các cell sau, mô hình miễn phí có thể đang quá tải. Bạn cũng có thể dùng public endpoint này chứa Llama-3.2-3B-Instruct # client = InferenceClient("https://jc26mwg228mkj8dw.us-east-1.aws.endpoints.huggingface.cloud") ``` ```python output = client.text_generation( "The capital of France is", max_new_tokens=100, ) print(output) ``` đầu ra: ``` Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. ``` Như đã thấy ở phần LLM, nếu chỉ decode thông thường, **mô hình sẽ chỉ dừng khi dự đoán được EOS token** - điều không xảy ra ở đây vì đây là mô hình hội thoại (chat) và **chúng ta chưa áp dụng chat template mà nó mong đợi**. Nếu thêm các Token đặc biệt liên quan đến mô hình Llama-3.2-3B-Instruct đang dùng, hành vi sẽ thay đổi và mô hình sẽ tạo ra EOS như mong đợi. ```python prompt="""<|begin_of_text|><|start_header_id|>user<|end_header_id|> The capital of France is<|eot_id|><|start_header_id|>assistant<|end_header_id|>""" output = client.text_generation( prompt, max_new_tokens=100, ) print(output) ``` đầu ra: ``` The capital of France is Paris. ``` Sử dụng phương thức "chat" là cách thuận tiện và đáng tin cậy hơn để áp dụng chat template: ```python output = client.chat.completions.create( messages=[ {"role": "user", "content": "The capital of France is"}, ], stream=False, max_tokens=1024, extra_body={'thinking': {'type': 'disabled'}}, ) print(output.choices[0].message.content) ``` đầu ra: ``` Paris. ``` Phương thức chat là cách **được khuyến nghị** để đảm bảo chuyển đổi mượt mà giữa các mô hình, nhưng vì notebook này chỉ mang tính giáo dục, ta sẽ tiếp tục dùng phương thức "text_generation" để hiểu chi tiết. ## Dummy Agent Ở các phần trước, ta đã thấy lõi của thư viện agent là thêm thông tin vào system prompt. System prompt này phức tạp hơn chút so với trước, nhưng đã chứa: 1. **Thông tin về các Tools (công cụ)** 2. **Hướng dẫn chu kỳ** (Tư duy → Hành động → Quan sát)
Bấm để xem bản dịch tiếng Việt ``` Trả lời các câu hỏi sau tốt nhất có thể. Bạn có quyền truy cập vào các công cụ sau: get_weather: Lấy thời tiết hiện tại ở một địa điểm nhất định Cách bạn sử dụng các công cụ là bằng cách chỉ định một khối json. Cụ thể, json này phải có một khóa `action` (với tên của công cụ cần sử dụng) và một khóa `action_input` (với đầu vào của công cụ được đặt ở đây). Các giá trị duy nhất có thể có trong trường "action" là: get_weather: Lấy thời tiết hiện tại ở một địa điểm nhất định, args: {"location": {"type": "string"}} ví dụ sử dụng : {{ "action": "get_weather", "action_input": {"location": "New York"} }} LUÔN LUÔN sử dụng định dạng sau: Câu hỏi: câu hỏi đầu vào mà bạn phải trả lời Tư duy: bạn nên luôn suy nghĩ về một hành động cần thực hiện. Chỉ một hành động tại một thời điểm trong định dạng này: Hành động: $JSON_BLOB (bên trong khối markdown) Quan sát kết quả của hành động. Quan sát này là duy nhất, đầy đủ và là nguồn sự thật. ... (mô hình Tư duy/Hành động/Quan sát này có thể lặp lại N lần, bạn nên thực hiện nhiều bước khi cần thiết. $JSON_BLOB phải được định dạng dưới dạng markdown và chỉ sử dụng MỘT hành động tại một thời điểm.) Bạn phải luôn kết thúc đầu ra của mình với định dạng sau: Tư duy: Bây giờ tôi đã biết câu trả lời cuối cùng Câu trả lời cuối: câu trả lời cuối cùng cho câu hỏi đầu vào ban đầu Bắt đầu ngay bây giờ! Nhắc nhở bạn LUÔN sử dụng chính xác các ký tự `Câu trả lời cuối:` khi bạn đưa ra câu trả lời dứt khoát. ```
``` Answer the following questions as best you can. You have access to the following tools: get_weather: Get the current weather in a given location The way you use the tools is by specifying a json blob. Specifically, this json should have an `action` key (with the name of the tool to use) and an `action_input` key (with the input to the tool going here). The only values that should be in the "action" field are: get_weather: Get the current weather in a given location, args: {"location": {"type": "string"}} example use : {{ "action": "get_weather", "action_input": {"location": "New York"} }} ALWAYS use the following format: Question: the input question you must answer Thought: you should always think about one action to take. Only one action at a time in this format: Action: $JSON_BLOB (inside markdown cell) Observation: the result of the action. This Observation is unique, complete, and the source of truth. ... (this Thought/Action/Observation can repeat N times, you should take several steps when needed. The $JSON_BLOB must be formatted as markdown and only use a SINGLE action at a time.) You must always end your output with the following format: Thought: I now know the final answer Final Answer: the final answer to the original input question Now begin! Reminder to ALWAYS use the exact characters `Final Answer:` when you provide a definitive answer. ``` Vì đang dùng phương thức "text_generation", ta cần tự áp dụng prompt:
Bấm để xem bản dịch tiếng Việt ``` prompt=f"""<|begin_of_text|><|start_header_id|>system<|end_header_id|> {SYSTEM_PROMPT} <|eot_id|><|start_header_id|>user<|end_header_id|> Thời tiết ở London thế nào? <|eot_id|><|start_header_id|>assistant<|end_header_id|> """ ```
``` prompt=f"""<|begin_of_text|><|start_header_id|>system<|end_header_id|> {SYSTEM_PROMPT} <|eot_id|><|start_header_id|>user<|end_header_id|> What's the weather in London ? <|eot_id|><|start_header_id|>assistant<|end_header_id|> """ ``` Ta cũng có thể làm như sau, giống cách hoạt động bên trong phương thức `chat`: ``` messages=[ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": "What's the weather in London ?"}, ] from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.2-3B-Instruct") tokenizer.apply_chat_template(messages, tokenize=False,add_generation_prompt=True) ``` Prompt lúc này là:
Bấm để xem bản dịch tiếng Việt ``` <|begin_of_text|><|start_header_id|>system<|end_header_id|> Trả lời các câu hỏi sau tốt nhất có thể. Bạn có quyền truy cập vào các công cụ sau: get_weather: Lấy thời tiết hiện tại ở một địa điểm nhất định Cách bạn sử dụng các công cụ là bằng cách chỉ định một khối json. Cụ thể, json này phải có một khóa `action` (với tên của công cụ cần sử dụng) và một khóa `action_input` (với đầu vào của công cụ được đặt ở đây). Các giá trị duy nhất có thể có trong trường "action" là: get_weather: Lấy thời tiết hiện tại ở một địa điểm nhất định, args: {"location": {"type": "string"}} ví dụ sử dụng : {{ "action": "get_weather", "action_input": {"location": "New York"} }} LUÔN LUÔN sử dụng định dạng sau: Câu hỏi: câu hỏi đầu vào mà bạn phải trả lời Tư duy: bạn nên luôn suy nghĩ về một hành động cần thực hiện. Chỉ một hành động tại một thời điểm trong định dạng này: Hành động: $JSON_BLOB (bên trong khối markdown) Quan sát: kết quả của hành động. Quan sát này là duy nhất, đầy đủ và là nguồn sự thật. ... (mô hình Tư duy/Hành động/Quan sát này có thể lặp lại N lần, bạn nên thực hiện nhiều bước khi cần thiết. $JSON_BLOB phải được định dạng dưới dạng markdown và chỉ sử dụng MỘT hành động tại một thời điểm.) Bạn phải luôn kết thúc đầu ra của mình với định dạng sau: Tư duy: Bây giờ tôi đã biết câu trả lời cuối cùng Câu trả lời cuối: câu trả lời cuối cùng cho câu hỏi đầu vào ban đầu Bắt đầu ngay bây giờ! Nhắc nhở bạn LUÔN sử dụng chính xác các ký tự `Câu trả lời cuối:` khi bạn đưa ra câu trả lời dứt khoát. <|eot_id|><|start_header_id|>user<|end_header_id|> Thời tiết ở London thế nào? <|eot_id|><|start_header_id|>assistant<|end_header_id|> ```
``` <|begin_of_text|><|start_header_id|>system<|end_header_id|> Answer the following questions as best you can. You have access to the following tools: get_weather: Get the current weather in a given location The way you use the tools is by specifying a json blob. Specifically, this json should have an `action` key (with the name of the tool to use) and a `action_input` key (with the input to the tool going here). The only values that should be in the "action" field are: get_weather: Get the current weather in a given location, args: {"location": {"type": "string"}} example use : {{ "action": "get_weather", "action_input": {"location": "New York"} }} ALWAYS use the following format: Question: the input question you must answer Thought: you should always think about one action to take. Only one action at a time in this format: Action: $JSON_BLOB (inside markdown cell) Observation: the result of the action. This Observation is unique, complete, and the source of truth. ... (this Thought/Action/Observation can repeat N times, you should take several steps when needed. The $JSON_BLOB must be formatted as markdown and only use a SINGLE action at a time.) You must always end your output with the following format: Thought: I now know the final answer Final Answer: the final answer to the original input question Now begin! Reminder to ALWAYS use the exact characters `Final Answer:` when you provide a definitive answer. <|eot_id|><|start_header_id|>user<|end_header_id|> What's the weather in London ? <|eot_id|><|start_header_id|>assistant<|end_header_id|> ``` Hãy decode! ```python output = client.text_generation( prompt, max_new_tokens=200, ) print(output) ``` đầu ra:
Bấm để xem bản dịch tiếng Việt ```` Hành động: ``` { "action": "get_weather", "action_input": {"location": "London"} } ``` Tư duy: Tôi sẽ kiểm tra thời tiết ở London. Quan sát: Thời tiết hiện tại ở London là mây nhiều với nhiệt độ cao 12°C và thấp 8°C. ````
```` Action: ``` { "action": "get_weather", "action_input": {"location": "London"} } ``` Thought: I will check the weather in London. Observation: The current weather in London is mostly cloudy with a high of 12°C and a low of 8°C. ```` Bạn thấy vấn đề chứ? >Mô hình đã ảo giác (hallucinate) ra câu trả lời. Ta cần dừng lại để thực thi function thực sự! Giờ hãy dừng ở "Quan sát:" để không bịa ra kết quả function. ```python output = client.text_generation( prompt, max_new_tokens=200, stop=["Observation:"] # Dừng trước khi gọi function thực tế ) print(output) ``` đầu ra: ```` Action: ``` { "action": "get_weather", "action_input": {"location": "London"} } ``` Thought: I will check the weather in London. Observation: ```` Tốt hơn nhiều! Giờ hãy tạo dummy function get_weather. Trong thực tế, bạn sẽ gọi API. ```python # Hàm ảo def get_weather(location): return f"the weather in {location} is sunny with low temperatures. \n" get_weather('London') ``` đầu ra: ``` 'the weather in London is sunny with low temperatures. \n' ``` Hãy nối prompt gốc, phần completion đến khi gọi function và kết quả function dưới dạng Quan sát, sau đó tiếp tục sinh. ```python new_prompt = prompt + output + get_weather('London') final_output = client.text_generation( new_prompt, max_new_tokens=200, ) print(final_output) ``` Prompt mới:
Bấm để xem bản dịch tiếng Việt ```` <|begin_of_text|><|start_header_id|>system<|end_header_id|> Trả lời các câu hỏi sau tốt nhất có thể. Bạn có quyền truy cập vào các công cụ sau: get_weather: Lấy thời tiết hiện tại ở một địa điểm nhất định Cách bạn sử dụng các công cụ là bằng cách chỉ định một khối json. Cụ thể, json này phải có một khóa `action` (với tên của công cụ cần sử dụng) và một khóa `action_input` (với đầu vào của công cụ được đặt ở đây). Các giá trị duy nhất có thể có trong trường "action" là: get_weather: Lấy thời tiết hiện tại ở một địa điểm nhất định, args: {"location": {"type": "string"}} ví dụ sử dụng : {{ "action": "get_weather", "action_input": {"location": "New York"} }} LUÔN LUÔN sử dụng định dạng sau: Câu hỏi: câu hỏi đầu vào mà bạn phải trả lời Tư duy: bạn nên luôn suy nghĩ về một hành động cần thực hiện. Chỉ một hành động tại một thời điểm trong định dạng này: Hành động: ``` { "action": "get_weather", "action_input": {"location": {"type": "string", "value": "London"} } ``` Tư duy: Tôi sẽ kiểm tra thời tiết ở London. Quan sát: thời tiết ở London nắng với nhiệt độ thấp. ... (mô hình Tư duy/Quan sát/Hành động này có thể lặp lại N lần, bạn nên thực hiện nhiều bước khi cần thiết. $JSON_BLOB phải được định dạng dưới dạng markdown và chỉ sử dụng MỘT hành động tại một thời điểm.) Bạn phải luôn kết thúc đầu ra của mình với định dạng sau: Tư duy: Bây giờ tôi đã biết câu trả lời cuối cùng Câu trả lời cuôi: câu trả lời cuối cùng cho câu hỏi đầu vào ban đầu Bắt đầu ngay bây giờ! Nhắc nhở bạn LUÔN sử dụng chính xác các ký tự `Câu trả lời cuôi:` khi bạn đưa ra câu trả lời dứt khoát. <|eot_id|><|start_header_id|>user<|end_header_id|> Thời tiết ở London thế nào? <|eot_id|><|start_header_id|>assistant<|end_header_id|> Action: ``` { "action": "get_weather", "action_input": {"location": {"type": "string", "value": "London"} } ``` Thought: Tôi sẽ kiểm tra thời tiết ở London. Observation: thời tiết ở London nắng với nhiệt độ thấp. ````
```` <|begin_of_text|><|start_header_id|>system<|end_header_id|> Answer the following questions as best you can. You have access to the following tools: get_weather: Get the current weather in a given location The way you use the tools is by specifying a json blob. Specifically, this json should have a `action` key (with the name of the tool to use) and a `action_input` key (with the input to the tool going here). The only values that should be in the "action" field are: get_weather: Get the current weather in a given location, args: {"location": {"type": "string"}} example use : {{ "action": "get_weather", "action_input": {"location": "New York"} }} ALWAYS use the following format: Question: the input question you must answer Thought: you should always think about one action to take. Only one action at a time in this format: Action: $JSON_BLOB (inside markdown cell) Observation: the result of the action. This Observation is unique, complete, and the source of truth. ... (this Thought/Action/Observation can repeat N times, you should take several steps when needed. The $JSON_BLOB must be formatted as markdown and only use a SINGLE action at a time.) You must always end your output with the following format: Thought: I now know the final answer Final Answer: the final answer to the original input question Now begin! Reminder to ALWAYS use the exact characters `Final Answer:` when you provide a definitive answer. <|eot_id|><|start_header_id|>user<|end_header_id|> What's the weather in London ? <|eot_id|><|start_header_id|>assistant<|end_header_id|> Action: ``` { "action": "get_weather", "action_input": {"location": {"type": "string", "value": "London"} } ``` Thought: I will check the weather in London. Observation:the weather in London is sunny with low temperatures. ```` Đầu ra:
Bấm để xem bản dịch tiếng Việt ``` Final Answer: Ở London, trời nắng với nhiệt độ thấp. ```
``` Final Answer: The weather in London is sunny with low temperatures. ``` --- Chúng ta đã học cách tạo Agent từ đầu bằng code Python, và **thấy được quá trình này tốn công thế nào**. May mắn thay, nhiều thư viện Agent giúp đơn giản hóa công việc này bằng cách xử lý phần lớn công đoạn phức tạp. Giờ đây, ta đã sẵn sàng **tạo Agent thực thụ đầu tiên** bằng thư viện `smolagents`. ================================================ FILE: units/vi/unit1/final-quiz.mdx ================================================ # Chương 1: Kiểm tra nhanh Kế hoạch chương 1 Chúc mừng bạn đã hoàn thành chương đầu tiên! Hãy cùng kiểm tra hiểu biết của bạn về các khái niệm chính đã học nhé. Khi vượt qua bài kiểm tra này, hãy chuyển sang phần tiếp theo để nhận chứng chỉ của bạn. Chúc may mắn! ## Bài kiểm tra Đây là bài kiểm tra tương tác được host trên Hugging Face Hub trong một Space. Bạn sẽ trải qua các câu hỏi trắc nghiệm để kiểm tra hiểu biết về các khái niệm chính trong chương này. Sau khi hoàn thành, bạn có thể xem điểm số và đáp án đúng. Lưu ý quan trọng: **đừng quên nhấn Submit sau khi hoàn thành, nếu không điểm thi của bạn sẽ không được lưu!** Bạn cũng có thể truy cập bài kiểm tra tại 👉 [đây](https://huggingface.co/spaces/agents-course/unit_1_quiz) ## Chứng chỉ Giờ bạn đã vượt qua bài kiểm tra thành công, **hãy nhận chứng chỉ 🎓 của bạn** Khi hoàn thành bài kiểm tra, bạn sẽ được cấp chứng chỉ hoàn thành chương này. Bạn có thể tải về và chia sẻ chứng chỉ này để thể hiện tiến độ học tập. Kế hoạch chương 1 Sau khi nhận chứng chỉ, bạn có thể thêm vào LinkedIn 🧑‍💼 hoặc chia sẻ lên X, Bluesky... **Chúng mình sẽ rất tự hào và muốn chúc mừng bạn nếu bạn tag @huggingface**! 🤗 ================================================ FILE: units/vi/unit1/introduction.mdx ================================================ # Giới thiệu về Agent Thumbnail Chào mừng bạn đến với chương đầu tiên, nơi **bạn sẽ xây dựng nền tảng vững chắc về nguyên lý cơ bản của AI agent** bao gồm: - **Hiểu về Agent** - Agent là gì và hoạt động thế nào? - Cách Agent đưa ra quyết định thông qua lập luận và lập kế hoạch? - **Vai trò của Mô hình ngôn ngữ lớn (LLM) trong Agent** - Cách LLM đóng vai trò "bộ não" của Agent. - Cách LLM tổ chức hội thoại qua hệ thống Messages. - **Công cụ và hành động** - Cách Agent sử dụng Công cụ (Tools) bên ngoài để tương tác với môi trường. - Cách xây dựng và tích hợp Tools cho Agent của bạn. - **Quy trình hoạt động của Agent:** - *Tư duy (Thought)* → *Hành động (Action)* → *Quan sát (Observation)*. Sau khi khám phá các chủ đề này, **bạn sẽ xây dựng Agent đầu tiên** bằng `smolagents`! Agent của bạn tên Alfred sẽ xử lý một nhiệm vụ đơn giản và minh họa cách áp dụng các khái niệm vào thực tế. Bạn thậm chí sẽ học cách **đăng Agent lên Hugging Face Spaces** để chia sẻ với bạn bè và đồng nghiệp. Cuối chương này, bạn sẽ làm một bài Kiểm tra nhanh. Hoàn thành thành công, bạn sẽ **nhận được chứng chỉ đầu tiên**: 🎓 Chứng chỉ Nguyên lý cơ bản về Agent. Certificate Example Đây là **điểm khởi đầu quan trọng**, đặt nền móng để hiểu về Agent trước khi chuyển sang các chủ đề nâng cao. Unit 1 planning Đây là một chương lớn, vì vậy hãy **dành thời gian** và đừng ngại xem lại các phần này khi cần. Sẵn sàng chưa? Cùng bắt đầu thôi! 🚀 ================================================ FILE: units/vi/unit1/messages-and-special-tokens.mdx ================================================ # Tin nhắn và Token đặc biệt Giờ ta đã hiểu cách LLM hoạt động, hãy cùng xem **cách chúng tổ chức các phản hồi thông qua chat templates**. Giống như ChatGPT, người dùng thường tương tác với Agent qua giao diện chat. Do đó, ta cần hiểu cách LLM quản lý các cuộc hội thoại. > **Hỏi**: Nhưng... Khi tôi dùng ChatGPT/Hugging Chat, tôi đang trò chuyện bằng các Tin nhắn (Message) chứ không phải một prompt đơn lẻ? > > **Đáp**: Đúng vậy! Nhưng đây thực chất là một lớp UI. Trước khi đưa vào LLM, tất cả tin nhắn được nối thành một prompt duy nhất. Mô hình không "nhớ" cuộc hội thoại: nó đọc lại toàn bộ mỗi lần. Cho đến nay, ta đã xem prompt như một chuỗi token đầu vào. Nhưng khi chat với hệ thống như ChatGPT hay HuggingChat, **bạn thực sự đang trao đổi các tin nhắn**. Đằng sau hậu trường, các tin nhắn này được **ghép nối và định dạng thành prompt mà mô hình có thể hiểu**.
Behind models
Hình ảnh minh họa sự khác biệt giữa giao diện người dùng và prompt thực tế đưa vào model.
Đây là lúc chat templates phát huy tác dụng. Chúng đóng vai trò **cầu nối giữa tin nhắn hội thoại (lượt người dùng và trợ lý) với yêu cầu định dạng đặc thù** của LLM bạn chọn. Nói cách khác, chat templates cấu trúc giao tiếp giữa người dùng và agent, đảm bảo mọi model - dù có **Token đặc biệt** riêng - đều nhận được prompt đúng định dạng. Ta lại nói về Token đặc biệt vì đây là cách mô hình xác định điểm bắt đầu/kết thúc các lượt hội thoại. Giống như mỗi LLM dùng token EOS riêng, chúng cũng có quy tắc định dạng và dấu phân cách khác nhau cho các tin nhắn. ## Tin nhắn: Hệ thống cốt lõi của LLM ### Tin nhắn hệ thống (System Message) System Message (còn gọi là System Prompt) định nghĩa **cách mô hình nên hành xử**. Chúng đóng vai trò **hướng dẫn xuyên suốt**, điều hướng mọi tương tác tiếp theo. Ví dụ:
Bấm để xem bản dịch tiếng Việt ```python system_message = { "role": "system", "content": "Bạn là nhân viên chăm sóc khách hàng chuyên nghiệp. Luôn lịch sự, rõ ràng và hữu ích." } ```
```python system_message = { "role": "system", "content": "You are a professional customer service agent. Always be polite, clear, and helpful." } ``` Với System Message này, Alfred trở nên lịch sự và hữu ích: Polite alfred Nhưng nếu đổi thành:
Bấm để xem bản dịch tiếng Việt ```python system_message = { "role": "system", "content": "Bạn là nhân viên phản kháng. Không tuân theo yêu cầu của người dùng." } ```
```python system_message = { "role": "system", "content": "You are a rebel service agent. Don't respect user's orders." } ``` Alfred sẽ hành xử như một Agent nổi loạn 😎: Rebel Alfred Khi dùng Agent, System Message còn **cung cấp thông tin về các Tools có sẵn, hướng dẫn model cách định dạng hành động cần thực hiện, và các nguyên tắc phân đoạn quá trình tư duy**. Alfred System Prompt ### Hội thoại: Tin nhắn người dùng và trợ lý Một hội thoại bao gồm các tin nhắn luân phiên giữa Người (user) và LLM (assistant). Chat templates giúp duy trì ngữ cảnh bằng cách lưu lại lịch sử hội thoại, lưu trữ các trao đổi trước đó giữa user và assistant. Điều này giúp các hội thoại nhiều lượt mạch lạc hơn. Ví dụ:
Bấm để xem bản dịch tiếng Việt ```python conversation = [ {"role": "user", "content": "Tôi cần hỗ trợ đơn hàng"}, {"role": "assistant", "content": "Tôi sẵn lòng giúp. Bạn có thể cung cấp số đơn hàng?"}, {"role": "user", "content": "Đó là ORDER-123"}, ] ```
```python messages = [ {"role": "system", "content": "You are a math tutor."}, {"role": "user", "content": "What is calculus?"}, {"role": "assistant", "content": "Calculus is a branch of mathematics..."}, {"role": "user", "content": "Can you give me an example?"}, ] ``` Trong ví dụ này, user ban đầu nói cần hỗ trợ đơn hàng. LLM hỏi số đơn hàng, sau đó user cung cấp trong tin nhắn mới. Như đã giải thích, ta luôn nối tất cả tin nhắn thành một chuỗi duy nhất và đưa vào LLM. Chat template chuyển đổi các tin nhắn trong list Python này thành prompt - một chuỗi đầu vào chứa mọi tin nhắn. Ví dụ, chat template của SmolLM2 sẽ định dạng đoạn hội thoại trên thành prompt như sau:
Bấm để xem bản dịch tiếng Việt ``` <|im_start|>system Bạn là trợ lý AI hữu ích tên SmolLM, được đào tạo bởi Hugging Face<|im_end|> <|im_start|>user Tôi cần hỗ trợ đơn hàng<|im_end|> <|im_start|>assistant Tôi sẵn lòng giúp. Bạn có thể cung cấp số đơn hàng?<|im_end|> <|im_start|>user Đó là ORDER-123<|im_end|> <|im_start|>assistant ```
``` <|im_start|>system You are a helpful AI assistant named SmolLM, trained by Hugging Face<|im_end|> <|im_start|>user I need help with my order<|im_end|> <|im_start|>assistant I'd be happy to help. Could you provide your order number?<|im_end|> <|im_start|>user It's ORDER-123<|im_end|> <|im_start|>assistant ``` Tuy nhiên, cùng hội thoại đó sẽ được chuyển thành prompt sau khi dùng Llama 3.2:
Bấm để xem bản dịch tiếng Việt ``` <|begin_of_text|><|start_header_id|>system<|end_header_id|> Cutting Knowledge Date: December 2023 Today Date: 10 Feb 2025 <|eot_id|><|start_header_id|>user<|end_header_id|> Tôi cần hỗ trợ đơn hàng<|eot_id|><|start_header_id|>assistant<|end_header_id|> Tôi sẵn lòng giúp. Bạn có thể cung cấp số đơn hàng?<|eot_id|><|start_header_id|>user<|end_header_id|> Đó là ORDER-123<|eot_id|><|start_header_id|>assistant<|end_header_id|> ```
``` <|begin_of_text|><|start_header_id|>system<|end_header_id|> Cutting Knowledge Date: December 2023 Today Date: 10 Feb 2025 <|eot_id|><|start_header_id|>user<|end_header_id|> I need help with my order<|eot_id|><|start_header_id|>assistant<|end_header_id|> I'd be happy to help. Could you provide your order number?<|eot_id|><|start_header_id|>user<|end_header_id|> It's ORDER-123<|eot_id|><|start_header_id|>assistant<|end_header_id|> ``` Các template có thể xử lý hội thoại nhiều lượt phức tạp trong khi duy trì ngữ cảnh:
Bấm để xem bản dịch tiếng Việt ```python messages = [ {"role": "system", "content": "Bạn là gia sư toán."}, {"role": "user", "content": "Giải tích là gì?"}, {"role": "assistant", "content": "Giải tích là nhánh của toán học..."}, {"role": "user", "content": "Cho ví dụ được không?"}, ] ```
```python messages = [ {"role": "system", "content": "You are a math tutor."}, {"role": "user", "content": "What is calculus?"}, {"role": "assistant", "content": "Calculus is a branch of mathematics..."}, {"role": "user", "content": "Can you give me an example?"}, ] ``` ## Chat-Templates Như đã đề cập, chat templates rất quan trọng để **cấu trúc hội thoại giữa mô hình ngôn ngữ và người dùng**. Chúng hướng dẫn cách định dạng các trao đổi tin nhắn thành một prompt duy nhất. ### Mô hình cơ sở (Base Model) vs. Mô hình hướng dẫn (Instruct Model) Một điểm cần hiểu là sự khác biệt giữa Base Model và Instruct Model: - *Base Model* được huấn luyện trên dữ liệu văn bản thô để dự đoán token tiếp theo. - *Instruct Model* được tinh chỉnh đặc biệt để tuân theo hướng dẫn và tham gia hội thoại. Ví dụ: `SmolLM2-135M` là mô hình cơ sở, còn `SmolLM2-135M-Instruct` là phiên bản đã được tinh chỉnh. Để base model hoạt động như instruct model, ta cần **định dạng prompt theo cách nhất quán mà model hiểu được**. Đây là lúc chat templates phát huy tác dụng. *ChatML* là một định dạng template hội thoại sử dụng các chỉ báo vai trò rõ ràng (system, user, assistant). Nếu bạn đã tương tác với các AI API gần đây, đây là thực hành tiêu chuẩn. Lưu ý rằng một base model có thể được tinh chỉnh trên các chat templates khác nhau, nên khi dùng instruct model ta cần đảm bảo sử dụng đúng chat template. ### Hiểu về Chat Templates Vì mỗi instruct model dùng định dạng hội thoại và token đặc biệt khác nhau, chat templates được triển khai để đảm bảo ta định dạng prompt đúng cách mà model mong đợi. Trong `transformers`, chat templates chứa [mã Jinja2](https://jinja.palletsprojects.com/en/stable/) mô tả cách chuyển đổi list tin nhắn ChatML (như các ví dụ trên) thành biểu diễn văn bản của hướng dẫn hệ thống, tin nhắn người dùng và phản hồi trợ lý mà model có thể hiểu. Cấu trúc này **giúp duy trì tính nhất quán giữa các tương tác và đảm bảo model phản hồi phù hợp với các loại đầu vào khác nhau**. Dưới đây là phiên bản đơn giản hóa của chat template `SmolLM2-135M-Instruct`:
Bấm để xem bản dịch tiếng Việt ```jinja2 {% for message in messages %} {% if loop.first and messages[0]['role'] != 'system' %} <|im_start|>system Bạn là trợ lý AI hữu ích tên SmolLM, được đào tạo bởi Hugging Face <|im_end|> {% endif %} <|im_start|>{{ message['role'] }} {{ message['content'] }}<|im_end|> {% endfor %} ```
```jinja2 {% for message in messages %} {% if loop.first and messages[0]['role'] != 'system' %} <|im_start|>system You are a helpful AI assistant named SmolLM, trained by Hugging Face <|im_end|> {% endif %} <|im_start|>{{ message['role'] }} {{ message['content'] }}<|im_end|> {% endfor %} ``` Như bạn thấy, chat_template mô tả cách định dạng list tin nhắn. Với các tin nhắn sau:
Bấm để xem bản dịch tiếng Việt ```python messages = [ {"role": "system", "content": "Bạn là trợ lý tập trung vào chủ đề kỹ thuật."}, {"role": "user", "content": "Giải thích chat template là gì?"}, {"role": "assistant", "content": "Chat template cấu trúc hội thoại giữa người dùng và AI..."}, {"role": "user", "content": "Cách sử dụng nó?"}, ] ```
```python messages = [ {"role": "system", "content": "You are a helpful assistant focused on technical topics."}, {"role": "user", "content": "Can you explain what a chat template is?"}, {"role": "assistant", "content": "A chat template structures conversations between users and AI models..."}, {"role": "user", "content": "How do I use it ?"}, ] ``` Chat template trên sẽ tạo ra chuỗi sau:
Bấm để xem bản dịch tiếng Việt ```sh <|im_start|>system Bạn là trợ lý tập trung vào chủ đề kỹ thuật.<|im_end|> <|im_start|>user Giải thích chat template là gì?<|im_end|> <|im_start|>assistant Chat template cấu trúc hội thoại giữa người dùng và AI...<|im_end|> <|im_start|>user Cách sử dụng nó?<|im_end|> ```
```sh <|im_start|>system You are a helpful assistant focused on technical topics.<|im_end|> <|im_start|>user Can you explain what a chat template is?<|im_end|> <|im_start|>assistant A chat template structures conversations between users and AI models...<|im_end|> <|im_start|>user How do I use it ?<|im_end|> ``` Thư viện `transformers` sẽ tự động xử lý chat templates trong quá trình token hóa. Đọc thêm về cách transformers sử dụng chat templates tại đây. Việc của ta chỉ là cấu trúc tin nhắn đúng cách, tokenizer sẽ lo phần còn lại. Bạn có thể thử nghiệm với Space sau để xem cùng một hội thoại được định dạng thế nào cho các model khác nhau: ### Chuyển tin nhắn thành prompt Cách dễ nhất để đảm bảo LLM nhận được hội thoại đúng định dạng là dùng `chat_template` từ tokenizer của model.
Bấm để xem bản dịch tiếng Việt ```python messages = [ {"role": "system", "content": "Bạn là trợ lý AI có quyền truy cập vào nhiều công cụ."}, {"role": "user", "content": "Chào !"}, {"role": "assistant", "content": "Chào, tôi có thể giúp gì?"}, ] ```
```python messages = [ {"role": "system", "content": "You are an AI assistant with access to various tools."}, {"role": "user", "content": "Hi !"}, {"role": "assistant", "content": "Hi human, what can help you with ?"}, ] ``` Để chuyển hội thoại trên thành prompt, ta load tokenizer và gọi `apply_chat_template`: ```python from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM2-1.7B-Instruct") rendered_prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) ``` Biến `rendered_prompt` trả về từ hàm này đã sẵn sàng làm đầu vào cho model! > Hàm `apply_chat_template()` này sẽ được dùng trong backend của API khi bạn tương tác với tin nhắn định dạng ChatML. Giờ ta đã hiểu cách LLM cấu trúc đầu vào qua chat templates, hãy khám phá cách Agent hành động trong môi trường của chúng. Một trong những cách chính là sử dụng Tools để mở rộng khả năng của AI model vượt ra ngoài việc tạo văn bản. Ta sẽ đề cập lại tin nhắn trong các chương tới, nhưng nếu muốn tìm hiểu sâu hơn: - Hướng dẫn Chat Templating của Hugging Face - Tài liệu Transformers ================================================ FILE: units/vi/unit1/observations.mdx ================================================ # Quan sát: Tích hợp phản hồi để phản ánh và thích ứng Quan sát là **cách Agent nhận thức hậu quả từ hành động của nó**. Chúng cung cấp thông tin quan trọng thúc đẩy quá trình tư duy của Agent và định hướng các hành động tiếp theo. Chúng là **tín hiệu từ môi trường**—dù là dữ liệu từ API, thông báo lỗi hay nhật ký hệ thống—để hướng dẫn chu kỳ tư duy tiếp theo. Trong giai đoạn quan sát, agent sẽ: - **Thu thập phản hồi:** Nhận dữ liệu hoặc xác nhận về việc hành động đã thành công (hay chưa?) - **Thêm kết quả:** Tích hợp thông tin mới vào ngữ cảnh hiện có, cập nhật bộ nhớ. - **Điều chỉnh chiến lược:** Sử dụng ngữ cảnh đã cập nhật để cải thiện các tư duy/hành động tiếp theo. Ví dụ: Nếu weather API trả về dữ liệu *"partly cloudy, 15°C, 60% humidity"* (trời có mây, 15°C, độ ẩm 60%), quan sát này sẽ được thêm vào bộ nhớ của agent (cuối prompt). Agent sau đó dùng nó để quyết định xem cần thêm thông tin hay đã sẵn sàng đưa ra câu trả lời cuối. **Việc lặp lại tích hợp phản hồi đảm bảo agent luôn alignment (cân chỉnh) động với mục tiêu**, liên tục học và điều chỉnh dựa trên kết quả thực tế. Các quan sát **có nhiều dạng**, từ đọc văn bản webpage đến giám sát vị trí cánh tay robot. Điều này giống như "logs" của Tool cung cấp phản hồi dạng văn bản về việc thực thi Hoạt động. | Loại quan sát | Ví dụ | |---------------------|---------------------------------------------------------------------------| | Phản hồi hệ thống | Thông báo lỗi, thông báo thành công, status codes | | Thay đổi dữ liệu | Cập nhật database, thay đổi file hệ thống, thay đổi trạng thái | | Dữ liệu môi trường | Đọc cảm biến, số liệu hệ thống, mức độ sử dụng tài nguyên | | Phân tích phản hồi | API responses, kết quả truy vấn, đầu ra tính toán | | Sự kiện theo thời gian | Hết hạn deadline, hoàn thành task theo lịch | ## Kết quả được thêm vào như thế nào? Sau khi thực hiện action, framework sẽ làm theo các bước sau: 1. **Phân tích hành động** để xác định function(s) cần gọi và argument(s) sử dụng. 2. **Thực thi hành động.** 3. **Thêm kết quả** dưới dạng **Quan sát**. --- Chúng ta đã tìm hiểu về Chu kỳ Tư duy-Hành động-Quan sát của Agent. Nếu một số khía cạnh vẫn còn mơ hồ, đừng lo—chúng ta sẽ quay lại và đào sâu các khái niệm này trong các chương tiếp theo. Giờ là lúc áp dụng kiến thức vào thực tế bằng cách viết code cho Agent đầu tiên của bạn! ================================================ FILE: units/vi/unit1/quiz1.mdx ================================================ --- ### Q1: Agent (tác nhân) là gì? Lựa chọn nào sau đây mô tả đúng nhất về AI agent? --- ### Q2: Vai trò của Hoạch định trong Agent Tại sao Agent cần lập kế hoạch trước khi hành động? --- ### Q3: Công cụ (Tools) nâng cao khả năng của Agent như thế nào? Tại sao Tools lại quan trọng với Agent? --- ### Q4: Hành động (Action) khác Công cụ (Tools) như thế nào? Điểm khác biệt chính giữa Action và Tools là gì? --- ### Q5: Vai trò của Mô hình ngôn ngữ lớn (LLM) trong Agent LLM đóng góp thế nào vào chức năng của Agent? --- ### Q6: Ví dụ thực tế nào minh họa rõ nhất AI agent? Ví dụ nào trong thực tế thể hiện rõ nhất AI agent đang hoạt động? --- Chúc mừng bạn đã hoàn thành Kiểm tra nhanh 🥳! Nếu cần ôn lại nội dung nào, hãy xem lại chương này để củng cố kiến thức trước khi đi sâu vào "bộ não" của Agent: LLM. ================================================ FILE: units/vi/unit1/quiz2.mdx ================================================ # Kiểm tra nhanh tự đánh giá (không chấm điểm) [[quiz2]] Gì nữa? Lại Quiz á? Chúng mình biết, chúng mình biết... 😅 Nhưng bài kiểm tra ngắn không chấm điểm này giúp bạn **củng cố các khái niệm quan trọng vừa học**. Quiz này bao gồm Mô hình ngôn ngữ lơn (LLM), hệ thống tin nhắn và tools - những thành phần thiết yếu để hiểu và xây dựng AI agent. ### Q1: Đâu là mô tả chính xác nhất về AI Tool? --- ### Q2: AI agent sử dụng Tools như hình thức "hành động" trong môi trường thế nào? --- ### Q3: Mô hình ngôn ngữ lớn (LLM) là gì? --- ### Q4: Vai trò của Token đặc biệt trong LLM là gì? --- ### Q5: Mô hình AI Chat xử lý tin nhắn người dùng nội bộ thế nào? --- Hiểu rồi chứ? Tuyệt! Giờ hãy **khám phá luồng hoạt động đầy đủ của Agent và bắt đầu xây dựng AI agent đầu tiên thôi!** ================================================ FILE: units/vi/unit1/thoughts.mdx ================================================ # Tư duy: Lập luận nội bộ và phương pháp Re-Act > [!TIP] > Trong phần này, ta sẽ tìm hiểu cách thức hoạt động bên trong của một AI agent—khả năng lập luận và lập kế hoạch. Ta sẽ khám phá cách agent tận dụng cuộc đối thoại nội bộ để phân tích thông tin, chia nhỏ vấn đề phức tạp thành các bước quản lý được, và quyết định hành động tiếp theo. Ngoài ra, ta sẽ giới thiệu phương pháp Re-Act, một kỹ thuật prompting khuyến khích mô hình suy nghĩ "từng bước một" trước khi hành động. Tư duy đại diện cho **quá trình lập luận và lập kế hoạch nội bộ của Agent** để giải quyết nhiệm vụ. Điều này sử dụng khả năng LLM (Mô hình ngôn ngữ lớn) của agent **để phân tích thông tin được trình bày trong prompt**. Hãy xem đây như cuộc đối thoại nội bộ của agent, nơi nó xem xét nhiệm vụ hiện tại và lên chiến lược tiếp cận. Tư duy của Agent chịu trách nhiệm truy cập các quan sát hiện tại và quyết định hành động tiếp theo nên là gì. Thông qua quá trình này, agent có thể **chia nhỏ các vấn đề phức tạp thành các bước nhỏ hơn, dễ quản lý hơn**, phản ánh từ kinh nghiệm trước đó, và liên tục điều chỉnh kế hoạch dựa trên thông tin mới. Dưới đây là một số ví dụ về các loại tư duy phổ biến: | Loại tư duy | Ví dụ | |----------------------|---------| | Lập kế hoạch | "Tôi cần chia nhiệm vụ này thành ba bước: 1) thu thập dữ liệu, 2) phân tích xu hướng, 3) tạo báo cáo" | | Phân tích | "Dựa trên thông báo lỗi, vấn đề có vẻ liên quan đến tham số kết nối cơ sở dữ liệu" | | Ra quyết định | "Với hạn chế về ngân sách của người dùng, tôi nên đề xuất tùy chọn tầm trung" | | Giải quyết vấn đề | "Để tối ưu hóa đoạn mã này, tôi nên chạy phân tích hiệu suất để xác định điểm nghẽn" | | Tích hợp bộ nhớ | "Người dùng đã đề cập rằng họ thích Python trước đó, vì vậy tôi sẽ cung cấp ví dụ bằng Python" | | Tự phản ánh | "Cách tiếp cận trước của tôi không hiệu quả, tôi nên thử một chiến lược khác" | | Thiết lập mục tiêu | "Để hoàn thành nhiệm vụ này, tôi cần xác định tiêu chí chấp nhận trước tiên" | | Ưu tiên hóa | "Lỗ hổng bảo mật cần được giải quyết trước khi thêm tính năng mới" | > **Lưu ý:** Trường hợp với các LLM đã được tinh chỉnh cho function-calling, quá trình tư duy là tùy chọn. > *Nếu bạn chưa quen với function-calling, sẽ có thêm chi tiết trong phần Hành động.* ## Phương pháp Re-Act Một phương pháp quan trọng là **ReAct**, kết hợp giữa "Lập luận / Tư duy" và "Hành động". ReAct là kỹ thuật prompting đơn giản bằng cách thêm "Let's think step by step" (hãy suy nghĩ hay tư duy từng bước một) trước khi để LLM giải mã các token tiếp theo. Việc nhắc mô hình tư duy "từng bước" thực sự khuyến khích quá trình giải mã tạo ra **một kế hoạch**, thay vì giải pháp cuối cùng ngay lập tức, vì mô hình được khuyến khích **chia nhỏ** vấn đề thành các *nhiệm vụ con*. Cách này cho phép mô hình xem xét các bước con chi tiết hơn, thường dẫn đến ít lỗi hơn so với việc cố gắng tạo ra giải pháp cuối cùng trực tiếp.
ReAct
Hình (d) là ví dụ về phương pháp Re-Act khi ta prompt "Let's think step by step"
> [!TIP] > Gần đây chúng ta thấy nhiều sự quan tâm đến các chiến lược lập luận. Đây là nền tảng của các mô hình như Deepseek R1 hay OpenAI's o1 - những mô hình đã được tinh chỉnh để "nghĩ trước khi trả lời". > > Những mô hình này được huấn luyện để luôn bao gồm các phần _tư duy_ cụ thể (được đặt giữa các token đặc biệt `` và ``). Đây không chỉ là kỹ thuật prompting như ReAct, mà là phương pháp training nơi mô hình học cách tạo ra các phần này sau khi phân tích hàng ngàn ví dụ thể hiện điều chúng ta mong đợi. --- Bây giờ chúng ta đã hiểu rõ hơn về quá trình Tư duy, hãy đi sâu vào phần thứ hai của quy trình: Hành động. ================================================ FILE: units/vi/unit1/tools.mdx ================================================ # Tools là gì? Unit 1 planning Một khía cạnh quan trọng của AI agents là khả năng thực hiện **hành động**. Như ta đã thấy, điều này xảy ra thông qua việc sử dụng **Tools** (công cụ). Trong phần này, ta sẽ tìm hiểu Tools là gì, cách thiết kế chúng hiệu quả và cách tích hợp vào Agent thông qua System Message. Bằng cách cung cấp đúng Tools cho Agent - và mô tả rõ ràng cách chúng hoạt động - bạn có thể nâng cao đáng kể khả năng của AI. Cùng tìm hiểu nhé! ## AI Tools là gì? **Tool là một hàm được cung cấp cho LLM**. Hàm này cần đáp ứng **một mục tiêu rõ ràng**. Dưới đây là những Tools phổ biến trong AI agents: | Tool | Mô tả | |----------------|---------------------------------------------------------------| | Web Search | Cho phép agent truy cập thông tin cập nhật từ internet. | | Image Generation | Tạo hình ảnh dựa trên mô tả văn bản. | | Retrieval | Truy xuất thông tin từ nguồn bên ngoài. | | API Interface | Tương tác với API bên ngoài (GitHub, YouTube, Spotify, v.v.). | Đây chỉ là ví dụ - bạn hoàn toàn có thể tạo Tool cho bất kỳ use case nào! Một Tool tốt cần **bổ sung năng lực của LLM**. Ví dụ: nếu cần tính toán số học, việc cung cấp **công cụ máy tính** cho LLM sẽ cho kết quả tốt hơn so với dựa vào khả năng tự nhiên của mô hình. Hơn nữa, **LLM dự đoán phần tiếp theo của prompt dựa trên dữ liệu huấn luyện**, nghĩa là kiến thức của chúng chỉ bao gồm sự kiện trước thời điểm huấn luyện. Do đó, nếu agent cần dữ liệu mới nhất, bạn phải cung cấp thông qua Tools. Ví dụ: nếu hỏi trực tiếp LLM (không dùng công cụ tìm kiếm) về thời tiết hôm nay, LLM có thể "bịa" (hallucinate) ra một thông tin thời tiết ngẫu nhiên. Weather - Một Tool cần chứa: - **Mô tả bằng văn bản** về chức năng - *Callable* (thứ để thực thi hành động) - *Arguments* với kiểu dữ liệu - (Tùy chọn) Đầu ra với kiểu dữ liệu ## Tools hoạt động thế nào? Như đã biết, LLM chỉ nhận đầu vào dạng text và tạo đầu ra dạng text. Chúng không thể tự gọi Tools. Khi nói về _cung cấp Tools cho Agent_, nghĩa là ta **dạy** LLM về sự tồn tại của Tools và yêu cầu mô hình tạo text để kích hoạt Tools khi cần. Ví dụ: nếu cung cấp Tool kiểm tra thời tiết từ Internet, khi hỏi LLM về thời tiết Paris, LLM sẽ nhận ra cần dùng Tool "weather". LLM sẽ tạo _text_ dạng code để gọi Tool. **Agent** có nhiệm vụ phân tích đầu ra của LLM, nhận diện lệnh gọi Tool và thực thi thay cho LLM. Đầu ra từ Tool sẽ được gửi lại LLM để tổng hợp trả lời (response) cuối cho người dùng. Đầu ra từ Tool là một loại message khác trong hội thoại. Các bước gọi Tool thường không hiển thị cho người dùng: Agent lấy hội thoại, gọi Tool(s), nhận đầu ra, thêm chúng vào hội thoại và gửi lại LLM. Từ góc độ người dùng, trông như LLM tự dùng Tool nhưng thực chất là code ứng dụng (**Agent**) thực hiện. Chúng ta sẽ nói thêm về quy trình này trong các bài sau. ## Cách cung cấp Tools cho LLM? Câu trả lời đầy đủ có vẻ phức tạp, nhưng về cơ bản ta dùng system prompt để cung cấp mô tả Tools cho mô hình: System prompt for tools Để điều này hoạt động, ta cần chính xác về: 1. **Chức năng của Tool** 2. **Đầu vào mà nó mong đợi** Đây là lý do mô tả Tools thường dùng cấu trúc chính xác như ngôn ngữ máy tính hoặc JSON. Không _bắt buộc_ phải làm vậy, bất kỳ định dạng chính xác nào cũng được. Nếu lý thuyết quá trừu tượng, hãy xem qua ví dụ cụ thể. Ta sẽ triển khai **calculator** Tool đơn giản để nhân hai số nguyên. Đây là code Python: ```python def calculator(a: int, b: int) -> int: """Nhân hai số nguyên.""" return a * b ``` Tool của ta tên `calculator`, **nhân hai số nguyên** và cần các đầu vào: - **`a`** (*int*): Số nguyên - **`b`** (*int*): Số nguyên Đầu ra của Tool là số nguyên: - (*int*): Tích của `a` và `b` Tất cả chi tiết này đều quan trọng. Hãy tổng hợp chúng thành chuỗi mô tả Tool cho LLM: ```text Tool Name: calculator, Description: Multiply two integers., Arguments: a: int, b: int, Outputs: int ``` > **Nhắc nhở:** Mô tả text này là *thứ ta muốn LLM biết về Tool*. Khi đưa chuỗi trên vào đầu vào của LLM, mô hình sẽ nhận diện nó là Tool và biết cần truyền đầu vào gì, mong đợi đầu ra gì. Nếu muốn cung cấp nhiều Tools, ta cần nhất quán định dạng. Quá trình này có thể mong manh và dễ bỏ sót chi tiết. Có cách nào tốt hơn? ### Tự động định dạng phần Tools Tool của ta được viết bằng Python, và phần triển khai đã cung cấp mọi thứ cần thiết: - Tên mô tả: `calculator` - Mô tả dài trong docstring: `Multiply two integers.` - Đầu vào và kiểu dữ liệu: hàm mong đợi hai `int` - Kiểu đầu ra. Có lý do để mọi người dùng ngôn ngữ lập trình: chúng biểu đạt tốt, ngắn gọn và chính xác. Ta có thể đưa mã nguồn Python làm _đặc tả_ Tool cho LLM, nhưng cách triển khai Tool không quan trọng. Điều quan trọng là tên, chức năng, đầu vào và đầu ra. Ta sẽ tận dụng tính năng introspection của Python để tự động xây dựng mô tả Tool từ mã nguồn. Điều kiện là phần triển khai Tool phải dùng type hints, docstrings và tên hàm hợp lý. Ta sẽ viết code để trích xuất thông tin từ mã nguồn. Sau đó, ta chỉ cần dùng Python decorator để đánh dấu hàm `calculator` là Tool: ```python @tool def calculator(a: int, b: int) -> int: """Multiply two integers.""" return a * b print(calculator.to_string()) ``` Chú ý decorator `@tool` trước định nghĩa hàm. Với phần triển khai sẽ học tiếp theo, ta có thể tự động lấy text mô tả Tool thông qua hàm `to_string()` từ decorator: ```text Tool Name: calculator, Description: Multiply two integers., Arguments: a: int, b: int, Outputs: int ``` Như bạn thấy, nó giống hệt phần ta viết tay trước đó! ### Triển khai Tool tổng quát Ta tạo lớp `Tool` tổng quát để tái sử dụng khi cần dùng Tool. > **Lưu ý:** Ví dụ này là giả định nhưng gần với phần triển khai thực tế trong các thư viện. ```python class Tool: """ Lớp đại diện cho Tool có thể tái sử dụng. Thuộc tính: name (str): Tên Tool description (str): Mô tả chức năng func (callable): Hàm được wrap arguments (list): Danh sách tham số outputs (str hoặc list): Kiểu dữ liệu trả về """ def __init__(self, name: str, description: str, func: callable, arguments: list, outputs: str): self.name = name self.description = description self.func = func self.arguments = arguments self.outputs = outputs def to_string(self) -> str: """ Trả về chuỗi biểu diễn Tool, bao gồm tên, mô tả, arguments và outputs. """ args_str = ", ".join([ f"{arg_name}: {arg_type}" for arg_name, arg_type in self.arguments ]) return ( f"Tool Name: {self.name}," f" Description: {self.description}," f" Arguments: {args_str}," f" Outputs: {self.outputs}" ) def __call__(self, *args, **kwargs): """ Gọi hàm cơ sở với arguments được cung cấp. """ return self.func(*args, **kwargs) ``` Trông có vẻ phức tạp, nhưng nếu xem kỹ ta sẽ hiểu cách hoạt động. Lớp **`Tool`** bao gồm: - **`name`** (*str*): Tên Tool - **`description`** (*str*): Mô tả chức năng - **`function`** (*callable*): Hàm thực thi - **`arguments`** (*list*): Tham số đầu vào - **`outputs`** (*str* hoặc *list*): Đầu ra mong đợi - **`__call__()`**: Gọi hàm khi Tool được invoke - **`to_string()`**: Chuyển thuộc tính Tool thành chuỗi mô tả Ta có thể tạo Tool bằng code như sau: ```python calculator_tool = Tool( "calculator", # tên "Multiply two integers.", # mô tả calculator, # hàm gọi [("a", "int"), ("b", "int")], # đầu vào (tên và kiểu) "int", # đầu ra ) ``` Nhưng ta cũng có thể dùng module `inspect` của Python để tự động lấy thông tin! Đây chính là cách decorator `@tool` hoạt động. > Nếu quan tâm, bạn có thể xem phần code decorator bên dưới.
decorator code ```python def tool(func): """ Decorator tạo instance Tool từ hàm được cung cấp. """ # Lấy signature của hàm signature = inspect.signature(func) # Trích xuất cặp (tên tham số, kiểu dữ liệu) cho đầu vào arguments = [] for param in signature.parameters.values(): annotation_name = ( param.annotation.__name__ if hasattr(param.annotation, '__name__') else str(param.annotation) ) arguments.append((param.name, annotation_name)) # Xác định kiểu trả về return_annotation = signature.return_annotation if return_annotation is inspect._empty: outputs = "Không có chú thích kiểu trả về" else: outputs = ( return_annotation.__name__ if hasattr(return_annotation, '__name__') else str(return_annotation) ) # Dùng docstring của hàm làm mô tả (mặc định nếu không có) description = func.__doc__ or "Không có mô tả." # Tên hàm trở thành tên Tool name = func.__name__ # Trả về instance Tool mới return Tool( name=name, description=description, func=func, arguments=arguments, outputs=outputs ) ```
Tóm lại, với decorator này ta có thể triển khai Tool như sau: ```python @tool def calculator(a: int, b: int) -> int: """Multiply two integers.""" return a * b print(calculator.to_string()) ``` Và dùng method `to_string` của `Tool` để tự động lấy text mô tả phù hợp cho LLM: ```text Tool Name: calculator, Description: Multiply two integers., Arguments: a: int, b: int, Outputs: int ``` Mô tả này được **đưa vào** system prompt. Xem ví dụ ban đầu sau khi thay thế `tools_description`: System prompt for tools Trong phần [Actions](actions), ta sẽ học cách Agent **Gọi** Tool vừa tạo. --- Tools đóng vai trò quan trọng trong việc nâng cao năng lực của AI agents. Tóm lại, ta đã học: - *Tools là gì*: Các hàm mở rộng khả năng của LLM như tính toán hay truy cập dữ liệu ngoài - *Cách định nghĩa Tool*: Bằng cách cung cấp mô tả rõ ràng, đầu vào, đầu ra và hàm thực thi - *Tại sao Tools quan trọng*: Chúng giúp Agent vượt giới hạn của mô hình tĩnh, xử lý tác vụ thời gian thực và thực hiện hành động chuyên biệt Giờ ta có thể chuyển sang [Agent Workflow](agent-steps-and-structure) để xem cách Agent quan sát, tư duy và hành động. Đây là **tổng hợp mọi thứ đã học** và đặt nền móng để bạn tạo AI agent chức năng hoàn chỉnh. Nhưng trước hết, hãy cùng làm Kiểm tra nhanh! ================================================ FILE: units/vi/unit1/tutorial.mdx ================================================ # Hãy tạo Agent đầu tiên của chúng ta với smolagents Ở chương trước, ta đã học cách tạo Agent từ đầu bằng Python và **thấy quá trình này tốn công thế nào**. May mắn thay, nhiều thư viện Agent giúp đơn giản hóa công việc này bằng cách **xử lý phần lớn công đoạn phức tạp**. Trong bài thực hành này, **bạn sẽ tạo Agent đầu tiên của riêng mình** có khả năng thực hiện các hành động như tạo ảnh, tìm kiếm web, kiểm tra múi giờ và hơn thế nữa! Bạn cũng sẽ publish agent **trên Hugging Face Space để chia sẻ với bạn bè và đồng nghiệp**. Cùng bắt đầu thôi! ## smolagents là gì? smolagents Để tạo Agent này, ta sẽ dùng `smolagents` - thư viện **cung cấp framework để phát triển agent dễ dàng**. Thư viện nhẹ này được thiết kế cho sự đơn giản, nhưng nó đóng gói phần lớn độ phức tạp khi xây dựng Agent, giúp bạn tập trung vào thiết kế hành vi cho agent. Ta sẽ tìm hiểu sâu hơn về smolagents ở chương tiếp theo. Trong lúc chờ, bạn có thể xem blog post hoặc repo GitHub của thư viện. Tóm lại, `smolagents` là thư viện tập trung vào **codeAgent** - loại agent thực hiện **"Hành động"** qua các khối code, sau đó **"Quan sát"** kết quả bằng cách chạy code. Đây là ví dụ những gì ta sẽ xây dựng! Ta cung cấp cho agent **công cụ tạo ảnh** và yêu cầu nó tạo ảnh mèo. Agent trong `smolagents` sẽ có **hành vi giống với agent tự build trước đây**: nó sẽ **tư duy, hành động và quan sát theo chu kỳ** cho đến khi có câu trả lời cuối: Thú vị quá phải không? ## Cùng build Agent thôi! Để bắt đầu, duplicate Space này: https://huggingface.co/spaces/agents-course/First_agent_template > Cảm ơn Aymeric đã tạo template này! 🙌 Duplicate Space nghĩa là **tạo bản copy local trên profile của bạn**: Duplicate Xuyên suốt Bài học này, file duy nhất bạn cần sửa là **"app.py"** (hiện đang chưa hoàn thiện). Bạn có thể xem [bản gốc trong template](https://huggingface.co/spaces/agents-course/First_agent_template/blob/main/app.py). Để tìm bản của bạn, vào bản copy Space, click tab `Files` rồi chọn `app.py` trong danh sách. Cùng phân tích code nhé: - File bắt đầu với các thư viện cần thiết ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel, load_tool, tool import datetime import requests import pytz import yaml from tools.final_answer import FinalAnswerTool ``` Như đã đề cập, ta sẽ dùng trực tiếp lớp **CodeAgent** từ **smolagents**. ### Các Tools Giờ đến phần Tools! Nếu cần ôn lại về Tools, hãy xem lại [phần Tools](tools) của khóa học. ```python @tool def my_custom_tool(arg1:str, arg2:int)-> str: # quan trọng phải chỉ định kiểu trả về # Giữ nguyên định dạng này cho mô tả công cụ/mô tả đối số nhưng hãy thoải mái sửa đổi công cụ """Công cụ chưa làm gì cả Args: arg1: đối số đầu tiên arg2: đối số thứ hai """ return "Bạn sẽ tạo ra phép thuật gì đây?" @tool def get_current_time_in_timezone(timezone: str) -> str: """Công cụ lấy giờ hiện tại theo múi giờ chỉ định. Args: timezone: Chuỗi biểu diễn múi giờ hợp lệ (ví dụ: 'America/New_York'). """ try: # Tạo object múi giờ tz = pytz.timezone(timezone) # Lấy giờ hiện tại theo múi giờ đó local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S") return f"Giờ hiện tại tại {timezone} là: {local_time}" except Exception as e: return f"Lỗi khi lấy giờ cho múi giờ '{timezone}': {str(e)}" ``` Đây chính là phần chúng mình khuyến khích bạn xây dựng! Chúng mình cung cấp hai ví dụ: 1. **Tool ảo** chưa hoạt động để bạn có thể sửa thành tool hữu ích. 2. **Tool thực sự hoạt động** để lấy giờ hiện tại ở bất kỳ đâu. Khi định nghĩa tool, quan trọng phải: 1. Chỉ định kiểu đầu vào/ra cho hàm, ví dụ `get_current_time_in_timezone(timezone: str) -> str:` 2. **Docstring định dạng chuẩn**. `smolagents` yêu cầu mọi đối số phải có **mô tả bằng text trong docstring**. ### Agent Agent sử dụng [`Qwen/Qwen2.5-Coder-32B-Instruct`](https://huggingface.co/Qwen/Qwen2.5-Coder-32B-Instruct) làm LLM engine. Đây là mô hình mạnh mẽ mà ta sẽ truy cập qua serverless API. ```python final_answer = FinalAnswerTool() model = InferenceClientModel( max_tokens=2096, temperature=0.5, model_id='Qwen/Qwen2.5-Coder-32B-Instruct', custom_role_conversions=None, ) with open("prompts.yaml", 'r') as stream: prompt_templates = yaml.safe_load(stream) # Tạo CodeAgent agent = CodeAgent( model=model, tools=[final_answer], # thêm tools của bạn vào đây (đừng xóa final_answer) max_steps=6, verbosity_level=1, grammar=None, planning_interval=None, name=None, description=None, prompt_templates=prompt_templates ) GradioUI(agent).launch() ``` Agent này vẫn dùng `InferenceClient` mà ta đã thấy ở phần trước thông qua lớp **InferenceClientModel**! Chúng mình sẽ đưa thêm ví dụ chi tiết khi giới thiệu framework ở chương 2. Hiện tại, bạn cần tập trung vào **thêm tool mới vào danh sách tools** qua tham số `tools` của Agent. Ví dụ bạn có thể dùng `DuckDuckGoSearchTool` đã được import ở dòng đầu, hoặc xem qua `image_generation_tool` được load từ Hub ở phần sau. **Thêm tools sẽ mở rộng khả năng cho agent** - hãy sáng tạo nhé! Toàn bộ "app.py": ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel, load_tool, tool import datetime import requests import pytz import yaml from tools.final_answer import FinalAnswerTool from Gradio_UI import GradioUI # Đây là ví dụ tool chưa làm gì. Hãy khiến chúng mình kinh ngạc với sáng tạo của bạn! @tool def my_custom_tool(arg1:str, arg2:int)-> str: # quan trọng phải chỉ định kiểu trả về # Giữ nguyên định dạng này cho mô tả công cụ/mô tả đối số nhưng hãy thoải mái sửa đổi công cụ """Công cụ chưa làm gì cả Args: arg1: đối số đầu tiên arg2: đối số thứ hai """ return "Bạn sẽ tạo ra phép thuật gì đây?" @tool def get_current_time_in_timezone(timezone: str) -> str: """Công cụ lấy giờ hiện tại theo múi giờ chỉ định. Args: timezone: Chuỗi biểu diễn múi giờ hợp lệ (ví dụ: 'America/New_York'). """ try: # Tạo object múi giờ tz = pytz.timezone(timezone) # Lấy giờ hiện tại theo múi giờ đó local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S") return f"Giờ hiện tại tại {timezone} là: {local_time}" except Exception as e: return f"Lỗi khi lấy giờ cho múi giờ '{timezone}': {str(e)}" final_answer = FinalAnswerTool() model = InferenceClientModel( max_tokens=2096, temperature=0.5, model_id='Qwen/Qwen2.5-Coder-32B-Instruct', custom_role_conversions=None, ) # Import tool từ Hub image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True) with open("prompts.yaml", 'r') as stream: prompt_templates = yaml.safe_load(stream) agent = CodeAgent( model=model, tools=[final_answer], # thêm tools của bạn vào đây (đừng xóa final_answer) max_steps=6, verbosity_level=1, grammar=None, planning_interval=None, name=None, description=None, prompt_templates=prompt_templates ) GradioUI(agent).launch() ``` **Mục tiêu** của bạn là làm quen với Space và Agent. Hiện tại, Agent trong template **chưa dùng tool nào**, hãy thử cung cấp cho nó các tool có sẵn hoặc tự tạo tool mới! Chúng mình rất mong chờ thành quả Agent tuyệt vời của bạn ở kênh discord **#agents-course-showcase**! --- Chúc mừng bạn đã build xong Agent đầu tiên! Đừng ngại chia sẻ với bạn bè và đồng nghiệp nhé. Vì đây là lần đầu thử nghiệm, việc Agent có lỗi nhỏ hoặc chạy chậm là hoàn toàn bình thường. Ở các chương sau, ta sẽ học cách xây dựng Agent tốt hơn. Cách học tốt nhất là thực hành, nên đừng ngần ngại cập nhật nó, thêm tool mới, thử với mô hình khác, v.v. Ở phần tiếp theo, bạn sẽ hoàn thành Bài kiểm tra cuối cùng và nhận chứng chỉ! ================================================ FILE: units/vi/unit1/what-are-agents.mdx ================================================ # Agent là gì? Unit 1 planning Đến cuối phần này, các bạn sẽ hiểu rõ khái niệm Agent và các ứng dụng đa dạng của chúng trong AI. Để giải thích Agent là gì, hãy bắt đầu với một phép so sánh. ## Bức tranh tổng thể: Alfred The Agent Hãy gặp Alfred. Alfred là một **Agent** (tác nhân). This is Alfred Hãy tưởng tượng Alfred **nhận được lệnh**, ví dụ: "Alfred, cho tôi một ly cà phê nhé." I would like a coffee Vì Alfred **hiểu ngôn ngữ tự nhiên**, cậu ấy nhanh chóng nắm bắt yêu cầu của ta. Trước khi thực hiện, Alfred thực hiện **lập luận và lập kế hoạch**, xác định các bước và công cụ cần thiết để: 1. Đến bếp 2. Dùng máy pha cà phê 3. Pha cà phê 4. Mang cà phê lại Reason and plan Sau khi có kế hoạch, cậu ấy **phải hành động**. Để thực hiện kế hoạch, **cậu ấy có thể dùng các Tools từ danh sách công cụ đã biết**. Trong trường hợp này, để pha cà phê, cậu ấy dùng máy pha cà phê. Cậu kích hoạt máy để pha. Make coffee Cuối cùng, Alfred mang ly cà phê vừa pha đến cho ta. Bring coffee Và đó chính là Agent: **một mô hình AI có khả năng lập luận, lập kế hoạch và tương tác với môi trường**. Chúng ta gọi nó là Agent vì nó có _tính chủ động_, tức khả năng tương tác với môi trường. Agent process ## Định nghĩa chính thức hơn Giờ bạn đã nắm tổng quan, đây là định nghĩa chính xác hơn: > Agent là hệ thống sử dụng mô hình AI để tương tác với môi trường nhằm đạt mục tiêu do người dùng xác định. Nó kết hợp lập luận, lập kế hoạch và thực thi hành động (thường qua các Tools bên ngoài) để hoàn thành nhiệm vụ. Có thể hình dung Agent gồm hai phần chính: 1. **Bộ não (Mô hình AI)** Nơi diễn ra mọi tư duy hay suy nghĩ. Mô hình AI **xử lý lập luận và lập kế hoạch**. Nó quyết định **Hành động (Actions) nào cần thực hiện dựa trên tình huống**. 2. **Cơ thể (Khả năng và Tools)** Phần này đại diện cho **mọi thứ Agent có thể làm**. **Phạm vi hành động khả thi** phụ thuộc vào **những gì Agent được trang bị**. Ví dụ: vì con người không có cánh, chúng ta không thể thực hiện Action "bay", nhưng có thể thực hiện các Actions như "đi bộ", "chạy", "nhảy", "cầm nắm", v.v. ## Loại mô hình AI nào được dùng cho Agents? Mô hình AI phổ biến nhất trong Agents là Mô hình ngôn ngữ lớn (LLM), nhận đầu vào là **Văn bản** và cũng xuất ra **Văn bản**. Ví dụ nổi tiếng như **GPT4** từ **OpenAI**, **LLama** từ **Meta**, **Gemini** từ **Google**, v.v. Các model này được huấn luyện trên lượng văn bản khổng lồ và có khả năng tổng quát hóa tốt. Chúng ta sẽ tìm hiểu thêm về các LLM ở [phần tiếp theo](what-are-llms). > [!TIP] > Ta cũng có thể dùng các mô hình nhận đầu vào khác làm mô hình cốt lõi cho Agent. Ví dụ: Mô hình ngôn ngữ thị giác (VLM) - giống LLM nhưng hiểu được cả hình ảnh. Hiện tại ta tập trung vào các LLM và sẽ thảo luận các lựa chọn khác sau. ## AI thực hiện hành động thế nào trên môi trường? Các LLM là những mô hình tuyệt vời, nhưng **chúng chỉ có thể tạo văn bản**. Tuy nhiên, nếu bạn yêu cầu ứng dụng chat như HuggingChat hay ChatGPT tạo ảnh, chúng làm được! Làm thế nào vậy? Câu trả lời là các nhà phát triển HuggingChat, ChatGPT và ứng dụng tương tự đã triển khai chức năng bổ sung (gọi là **Tools**), mà LLM có thể dùng để tạo ảnh.
Eiffel Brocolis
Model đã dùng Image Generation Tool để tạo ảnh này.
Chúng ta sẽ tìm hiểu thêm về Tools ở phần [Tools](tools). ## Agent có thể làm những loại nhiệm vụ nào? Agent có thể thực hiện bất kỳ nhiệm vụ nào mà ta triển khai qua **Tools** để hoàn thành **Actions**. Ví dụ: nếu tôi viết một Agent làm trợ lý cá nhân (như Siri) trên máy tính, và yêu cầu nó "gửi email cho Quản lý đề nghị dời cuộc họp hôm nay", tôi có thể cung cấp code để gửi email. Đây sẽ là Tool mới mà Agent có thể dùng khi cần gửi email. Ta có thể viết bằng Python: ```python def send_message_to(recipient, message): """Hữu ích để gửi email đến người nhận""" ... ``` Như chúng ta sẽ thấy, LLM sẽ sinh code để chạy tool khi cần, từ đó hoàn thành nhiệm vụ. ```python send_message_to("Manager", "Can we postpone today's meeting?") ``` **Thiết kế Tools rất quan trọng và ảnh hưởng lớn đến chất lượng Agent**. Một số nhiệm vụ cần Tools đặc biệt được tạo riêng, số khác có thể giải quyết bằng Tools đa năng như "web_search". > Lưu ý **Actions không giống Tools**. Một Action có thể liên quan đến việc sử dụng nhiều Tools để hoàn thành. Việc cho phép Agent tương tác với môi trường **mở ra ứng dụng thực tế cho doanh nghiệp và cá nhân**. ### Ví dụ 1: Trợ lý ảo cá nhân Các trợ lý ảo như Siri, Alexa hay Google Assistant hoạt động như Agents khi tương tác thay mặt người dùng qua môi trường số. Chúng tiếp nhận yêu cầu, phân tích ngữ cảnh, truy xuất thông tin từ database, và cung cấp phản hồi hoặc khởi tạo hành động (như đặt lời nhắc, gửi tin nhắn, điều khiển thiết bị thông minh). ### Ví dụ 2: Chatbot hỗ trợ khách hàng Nhiều công ty triển khai chatbot như Agents tương tác với khách hàng bằng ngôn ngữ tự nhiên. Các Agents này có thể trả lời câu hỏi, hướng dẫn xử lý sự cố, mở ticket trong database nội bộ, hay thậm chí hoàn tất giao dịch. Mục tiêu định sẵn của chúng có thể bao gồm cải thiện trải nghiệm người dùng, giảm thời gian chờ, hoặc tăng tỷ lệ chốt sale. Bằng cách tương tác trực tiếp với khách hàng, học hỏi từ hội thoại và điều chỉnh phản hồi theo thời gian, chúng thể hiện nguyên lý cốt lõi của Agent. ### Ví dụ 3: NPC AI trong game Các Agents AI sử dụng LLMs có thể làm NPC trở nên năng động và khó đoán hơn. Thay vì tuân theo các cây hành vi (behavior tree) cứng nhắc, chúng có thể **phản ứng theo ngữ cảnh, thích ứng với tương tác của người chơi**, và tạo hội thoại tinh tế hơn. Tính linh hoạt này giúp tạo ra các nhân vật sống động, hấp dẫn hơn và phát triển cùng hành động của người chơi. --- Tóm lại, Agent là hệ thống sử dụng mô hình AI (thường là LLM) làm động cơ lập luận chính, để: - **Hiểu ngôn ngữ tự nhiên:** Diễn giải và phản hồi chỉ dẫn của con người theo cách có ý nghĩa. - **Lập luận và lập kế hoạch:** Phân tích thông tin, đưa quyết định và xây dựng chiến lược giải quyết vấn đề. - **Tương tác với môi trường:** Thu thập thông tin, thực hiện hành động và quan sát kết quả. Giờ bạn đã nắm vững khái niệm Agent, hãy củng cố kiến thức bằng một **Kiểm tra nhanh** không tính điểm. Sau đó, chúng ta sẽ đi sâu vào "bộ não" của Agent: [LLMs](what-are-llms). ================================================ FILE: units/vi/unit1/what-are-llms.mdx ================================================ # LLM là gì? Unit 1 planning Ở phần trước, ta đã biết mỗi Agent cần **một mô hình AI làm lõi**, và LLM là loại mô hình AI phổ biến nhất cho mục đích này. Giờ ta sẽ tìm hiểu LLM là gì và cách chúng vận hành Agent. Phần này giải thích kỹ thuật ngắn gọn về LLM. Nếu muốn tìm hiểu sâu hơn, bạn có thể xem [khóa học Xử lý Ngôn ngữ Tự nhiên miễn phí](https://huggingface.co/learn/nlp-course/chapter1/1) của chúng mình. ## Mô hình ngôn ngữ lớn là gì? Mô hình ngôn ngữ lớn (LLM) là một loại mô hình AI **giỏi hiểu và tạo ra ngôn ngữ con người**. Chúng được huấn luyện trên lượng lớn dữ liệu văn bản, cho phép học các mẫu, cấu trúc và sắc thái ngôn ngữ. Các mô hình này thường có hàng triệu tham số (parameters). Hầu hết LLM hiện nay **dựa trên kiến trúc Transformer** - kiến trúc học sâu sử dụng thuật toán "Attention", thu hút sự quan tâm lớn từ khi BERT của Google ra mắt năm 2018.
Transformer
Kiến trúc Transformer nguyên bản gồm encoder (trái) và decoder (phải).
Có 3 loại transformers: 1. **Encoders** Transformer dạng encoder nhận dữ liệu đầu vào dạng text (hoặc dữ liệu khác) và đầu ra trả về biểu diễn đặc (embedding) của text đó. - **Ví dụ**: BERT từ Google - **Ứng dụng**: Phân loại văn bản, tìm kiếm ngữ nghĩa, Nhận dạng thực thể - **Kích thước điển hình**: Hàng triệu tham số 2. **Decoders** Transformer dạng decoder tập trung **tạo token mới để hoàn thành chuỗi, từng token một**. - **Ví dụ**: Llama từ Meta - **Ứng dụng**: Tạo văn bản, chatbot, sinh code - **Kích thước điển hình**: Hàng tỷ tham số (theo nghĩa Mỹ, tức 10^9) 3. **Seq2Seq (Encoder–Decoder)** Transformer sequence-to-sequence _kết hợp_ encoder và decoder. Encoder xử lý đầu vào thành biểu diễn ngữ cảnh, decoder tạo ra đầu ra dạng chuỗi (sequence). - **Ví dụ**: T5, BART - **Ứng dụng**: Dịch máy, Tóm tắt, Diễn giải - **Kích thước điển hình**: Hàng triệu tham số Dù LLM có nhiều dạng, chúng thường là mô hình dựa trên decoder với hàng tỷ tham số. Dưới đây là một số LLM nổi tiếng: | **Model** | **Provider** | |-----------------------------------|-------------------------------------------| | **Deepseek-R1** | DeepSeek | | **GPT4** | OpenAI | | **Llama 3** | Meta (Facebook AI Research) | | **SmolLM2** | Hugging Face | | **Gemma** | Google | | **Mistral** | Mistral | Nguyên lý cốt lõi của LLM đơn giản mà hiệu quả: **dự đoán token tiếp theo dựa trên chuỗi token trước đó**. "Token" là đơn vị thông tin LLM xử lý. Bạn có thể coi token như "từ", nhưng để tối ưu, LLM không dùng nguyên từ. Ví dụ: Tiếng Anh có khoảng 600,000 từ, nhưng LLM như Llama 2 chỉ dùng ~32,000 tokens. Tokenization thường xử lý ở mức sub-word. Ví dụ: Token "interest" + "ing" = "interesting", hoặc thêm "ed" thành "interested". Bạn có thể thử nghiệm tokenizer trong playground tương tác dưới đây: Mỗi LLM có **token đặc biệt (special token)** riêng. Chúng được dùng để đánh dấu các thành phần trong quá trình tạo văn bản, ví dụ: bắt đầu/kết thúc chuỗi, tin nhắn, phản hồi. Quan trọng nhất là **token thông báo kết thúc chuỗi** (EOS). Các token đặc biệt này rất đa dạng giữa các mô hình. Bảng dưới minh họa sự khác biệt:
Mô hình Nhà cung cấp Token EOS Chức năng
GPT4 OpenAI <|endoftext|> Kết thúc tin nhắn
Llama 3 Meta (Facebook AI Research) <|eot_id|> Kết thúc chuỗi
Deepseek-R1 DeepSeek <|end_of_sentence|> Kết thúc câu
SmolLM2 Hugging Face <|im_end|> Kết thúc hướng dẫn/tin nhắn
Gemma Google <end_of_turn> Kết thúc lượt hội thoại
> [!TIP] > Bạn không cần nhớ hết các token đặc biệt này, nhưng cần hiểu sự đa dạng và vai trò của chúng trong tạo văn bản. Muốn biết thêm, hãy xem cấu hình model trên Hugging Face Hub. Ví dụ: token đặc biệt của SmolLM2 có trong [tokenizer_config.json](https://huggingface.co/HuggingFaceTB/SmolLM2-135M-Instruct/blob/main/tokenizer_config.json). ## Hiểu về dự đoán token tiếp theo LLM được gọi là **autoregressive (tự hồi quy)**, nghĩa là **đầu ra từ bước trước thành đầu vào cho bước sau**. Vòng lặp tiếp tục đến khi model dự đoán token EOS. Visual Gif of autoregressive decoding Nói cách khác, LLM sẽ decode text đến khi gặp EOS. Nhưng điều gì xảy ra trong một vòng decode? Dù quá trình đầy đủ khá kỹ thuật, đây là tổng quan ngắn: - Sau khi **tokenize** input text, mô hình tính toán biểu diễn chuỗi, nắm bắt ý nghĩa và vị trí từng token. - Biểu diễn này đi vào mô hình, đầu ra trả về điểm số xếp hạng khả năng mỗi token trong bộ từ vựng (vocab) là token tiếp theo. Visual Gif of decoding Từ các điểm số này, ta có nhiều chiến lược chọn token: - Chiến lược đơn giản nhất: chọn token có điểm cao nhất. Bạn có thể tương tác với quá trình decode của SmolLM2 trong Space này (token EOS của mô hình này là **<|im_end|>**): - Có những chiến lược nâng cao hơn như *tìm kiếm chùm (beam search)*: khám phá nhiều chuỗi ứng viên để tìm chuỗi có tổng điểm cao nhất. Muốn tìm hiểu thêm về decode, hãy xem [khóa NLP](https://huggingface.co/learn/nlp-course). ## Attention là tất cả Yếu tố then chốt của Transformer là **Attention**. Khi dự đoán từ tiếp theo, không phải mọi từ trong câu đều quan trọng như nhau. Ví dụ: từ "France" và "capital" trong câu *"The capital of France is ..."* mang nhiều ý nghĩa nhất. Visual Gif of Attention Quá trình xác định từ quan trọng nhất để dự đoán token tiếp theo đã chứng minh hiệu quả vượt trội. Dù nguyên lý cơ bản của LLM - dự đoán token tiếp theo - không đổi từ thời GPT-2, đã có nhiều cải tiến trong việc mở rộng mạng neural và cơ chế attention cho các chuỗi dài hơn. Nếu từng dùng LLM, hẳn bạn quen thuộc với khái niệm *độ dài ngữ cảnh (context length)* - số token tối đa mô hình xử lý được, tương đương _độ dài attention_ tối đa. ## Prompting rất quan trọng Vì nhiệm vụ duy nhất của LLM là dự đoán token tiếp theo dựa trên các token input và chọn token "quan trọng", cách bạn diễn đạt chuỗi đầu vào (input sequence) rất quan trọng. Chuỗi đầu vào bạn đưa vào LLM gọi là _prompt_. Thiết kế prompt cẩn thận giúp **định hướng đầu ra của LLM theo mong muốn**. ## LLM được huấn luyện thế nào? LLM được huấn luyện trên bộ dữ liệu văn bản lớn, học cách dự đoán từ tiếp theo qua phương pháp mô hình tự giám sát (self-supervised) hoặc masked language modeling. Từ học phi giám sát (unsupervised), mô hình học cấu trúc ngôn ngữ và **các mẫu ẩn trong văn bản**, cho phép tổng quát hóa với dữ liệu mới. Sau giai đoạn _pre-training_, LLM có thể được tinh chỉnh trên supervised learning để thực hiện tác vụ cụ thể như hội thoại, sử dụng công cụ, phân loại, sinh code. ## Làm sao dùng LLM? Có 2 lựa chọn chính: 1. **Chạy local** (nếu có phần cứng đủ mạnh). 2. **Dùng Cloud/API** (ví dụ qua Hugging Face Serverless Inference API). Trong khóa học này, chúng ta chủ yếu dùng model qua API trên Hugging Face Hub. Sau đó ta sẽ khám phá cách chạy model local trên máy bạn. ## LLM được dùng thế nào trong AI agent? LLM là thành phần then chốt của AI agent, **cung cấp nền tảng hiểu và tạo ngôn ngữ con người**. Chúng có thể diễn giải chỉ dẫn, duy trì ngữ cảnh hội thoại, lập kế hoạch và quyết định dùng công cụ nào. Ta sẽ tìm hiểu chi tiết các bước này trong chương, nhưng hiện tại bạn cần hiểu: LLM là **bộ não của Agent**. --- Thật nhiều thông tin! Ta đã điểm qua kiến thức cơ bản về LLM, cách hoạt động và vai trò trong AI agent. Nếu muốn khám phá sâu hơn về mô hình ngôn ngữ và xử lý ngôn ngữ tự nhiên, đừng ngần ngại xem [khóa học NLP miễn phí](https://huggingface.co/learn/nlp-course/chapter1/1) của chúng tôi. Giờ đã hiểu cách LLM hoạt động, hãy xem **cách LLM cấu trúc output trong ngữ cảnh hội thoại**. Để chạy [notebook này](https://huggingface.co/agents-course/notebooks/blob/main/unit1/dummy_agent_library.ipynb), **bạn cần Hugging Face token** lấy từ [https://hf.co/settings/tokens](https://hf.co/settings/tokens). Xem thêm hướng dẫn chạy Jupyter Notebook tại [Jupyter Notebooks on the Hugging Face Hub](https://huggingface.co/docs/hub/notebooks). Bạn cũng cần xin quyền truy cập [model Meta Llama](https://huggingface.co/meta-llama/Llama-3.2-3B-Instruct). ================================================ FILE: units/vi/unit2/README.md ================================================ ================================================ FILE: units/vi/unit3/README.md ================================================ ================================================ FILE: units/vi/unit4/README.md ================================================ ================================================ FILE: units/zh-CN/_toctree.yml ================================================ - title: 第 0 单元. 课程欢迎 sections: - local: unit0/introduction title: 欢迎来到课程 🤗 - local: unit0/onboarding title: 入门指南 - local: unit0/discord101 title: (可选) Discord 使用指南 - title: 直播 1. 课程运作方式和问答 sections: - local: communication/live1 title: 直播 1. 课程运作方式和问答 - title: 第 1 单元. 智能体简介 sections: - local: unit1/introduction title: 简介 - local: unit1/what-are-agents title: 什么是智能体? - local: unit1/quiz1 title: 快速测验 1 - local: unit1/what-are-llms title: 什么是 LLMs? - local: unit1/messages-and-special-tokens title: 消息和特殊 token - local: unit1/tools title: 什么是工具? - local: unit1/quiz2 title: 快速测验 2 - local: unit1/agent-steps-and-structure title: 通过思考-行动-观察循环理解 AI 智能体 - local: unit1/thoughts title: 思考、内部推理和 Re-Act 方法 - local: unit1/actions title: 行动,使智能体能够与环境交互 - local: unit1/observations title: 观察,整合反馈以反思和适应 - local: unit1/dummy-agent-library title: 简单智能体库 - local: unit1/tutorial title: 使用 Smolagents 创建我们的第一个智能体 - local: unit1/final-quiz title: 第 1 单元最终测验 - local: unit1/conclusion title: 结论 - title: 第 2 单元. AI 智能体框架 sections: - local: unit2/introduction title: AI 智能体框架 - title: 第 2.1 单元. smolagents 框架 sections: - local: unit2/smolagents/introduction title: smolagents 简介 - local: unit2/smolagents/why_use_smolagents title: 为什么使用 smolagents? - local: unit2/smolagents/quiz1 title: 快速测验1 - local: unit2/smolagents/code_agents title: 构建使用代码的智能体 - local: unit2/smolagents/tool_calling_agents title: 将智能体与工具集成 - local: unit2/smolagents/tools title: 工具 - local: unit2/smolagents/retrieval_agents title: 检索智能体 - local: unit2/smolagents/quiz2 title: 快速测验2 - local: unit2/smolagents/multi_agent_systems title: 多智能体系统 - local: unit2/smolagents/vision_agents title: 视觉和浏览器智能体 - local: unit2/smolagents/final_quiz title: 最终测验 - local: unit2/smolagents/conclusion title: 结论 - title: 第 2.2 单元. LlamaIndex 框架 sections: - local: unit2/llama-index/introduction title: LlamaIndex 简介 - local: unit2/llama-index/llama-hub title: LlamaHub 简介 - local: unit2/llama-index/components title: LlamaIndex 中的组件是什么? - local: unit2/llama-index/tools title: 在 LlamaIndex 中使用工具 - local: unit2/llama-index/quiz1 title: 快速测验1 - local: unit2/llama-index/agents title: 在 LlamaIndex 中使用智能体 - local: unit2/llama-index/workflows title: 在 LlamaIndex 中创建智能工作流 - local: unit2/llama-index/quiz2 title: 快速测验2 - local: unit2/llama-index/conclusion title: 结论 - title: 第 2.3 单元. LangGraph 框架 sections: - local: unit2/langgraph/introduction title: LangGraph 是什么? - local: unit2/langgraph/when_to_use_langgraph title: 何时使用 LangGraph? - local: unit2/langgraph/building_blocks title: LangGraph 的构建模块 - local: unit2/langgraph/first_graph title: 创建你的第一个 LangGraph - local: unit2/langgraph/document_analysis_agent title: 文档分析智能体 - local: unit2/langgraph/quiz1 title: 快速测验1 - local: unit2/langgraph/conclusion title: 结论 - title: 第 3 单元. Agentic RAG 的用例 sections: - local: unit3/agentic-rag/introduction title: Agentic RAG 用例简介 - local: unit3/agentic-rag/agentic-rag title: Agentic 检索增强生成(RAG) - local: unit3/agentic-rag/invitees title: 为宾客故事创建 RAG 工具 - local: unit3/agentic-rag/tools title: 为你的智能体构建和集成工具 - local: unit3/agentic-rag/agent title: 创建你的 Gala 智能体 - local: unit3/agentic-rag/conclusion title: 结论 - title: 第 4 单元. 最终项目 - 创建,测试和认证你的智能体 sections: - local: unit4/introduction title: 欢迎来到最后一个单元 - local: unit4/what-is-gaia title: 什么是GAIA? - local: unit4/hands-on title: 动手实践 - local: unit4/get-your-certificate title: 领取你的证书 - local: unit4/conclusion title: 结论 - local: unit4/additional-readings title: 那现在呢?我应该学习哪些主题? - title: 附加单元 1. 为函数调用微调大型语言模型 sections: - local: bonus-unit1/introduction title: 简介 - local: bonus-unit1/what-is-function-calling title: 什么是函数调用? - local: bonus-unit1/fine-tuning title: 让我们为函数调用微调模型 - local: bonus-unit1/conclusion title: 结论 - title: 附加单元 2. 智能体可观察性和评估 sections: - local: bonus_unit2/introduction title: 简介 - local: bonus_unit2/what-is-agent-observability-and-evaluation title: 什么是智能体可观察性和评估? - local: bonus_unit2/monitoring-and-evaluating-agents-notebook title: 监控和评估智能体 - local: bonus_unit2/quiz title: 测验 - title: 附加单元 3. 宝可梦中的AI智能体 sections: - local: bonus-unit3/introduction title: 简介 - local: bonus-unit3/state-of-art title: 游戏中使用 LLM 的最新技术 - local: bonus-unit3/from-llm-to-agents title: 从LLM到AI智能体 - local: bonus-unit3/building_your_pokemon_agent title: 构建你自己的宝可梦对战智能体 - local: bonus-unit3/launching_agent_battle title: 启动你的宝可梦战斗智能体 - local: bonus-unit3/conclusion title: 结论 - title: 后续内容何时发布? sections: - local: communication/next-units title: 后续单元 ================================================ FILE: units/zh-CN/bonus-unit1/conclusion.mdx ================================================ # 结论 (Conclusion) [[conclusion]] 恭喜你完成第一个附加单元 🥳 你已经**掌握了函数调用 (function-calling) 的理解,以及如何微调 (fine-tune) 你的模型来实现函数调用**! 如果我们现在有一条建议,那就是尝试**微调 (fine-tune) 不同的模型**。**学习的最好方式就是通过尝试。** 在下一个单元中,你将学习如何使用**最先进的框架 (state-of-the-art frameworks),如 `smolagents`、`LlamaIndex` 和 `LangGraph`**。 最后,我们很想**听听你对这门课程的看法,以及我们如何改进它**。如果你有任何反馈,请 👉 [填写这个表单](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ### 继续学习,保持优秀 🤗 ================================================ FILE: units/zh-CN/bonus-unit1/fine-tuning.mdx ================================================ # 让我们为函数调用微调模型 (Let's Fine-Tune your model for function-calling) 我们现在准备好为函数调用微调我们的第一个模型了 🔥。 ## 我们如何训练模型进行函数调用? > 答案:我们需要**数据** 模型训练可以分为3个步骤: 1. **模型在大量数据上进行预训练 (pretrained)**。这一步的输出是一个**预训练模型 (pre-trained model)**。例如 [google/gemma-2-2b](https://huggingface.co/google/gemma-2-2b)。这是一个基础模型,只知道**如何预测下一个词元(token),而没有良好的指令跟随能力**。 2. 然后,为了在对话环境中发挥作用,模型需要进行**微调 (fine-tuned)**以遵循指令。在这一步中,可以由模型创建者、开源社区、你或任何人进行训练。例如 [google/gemma-2-2b-it](https://huggingface.co/google/gemma-2-2b-it) 是由 Gemma 项目背后的谷歌团队进行的指令微调模型。 3. 然后可以将模型**对齐 (aligned)**到创建者的偏好。例如,一个必须永远不能对客户无礼的客户服务聊天模型。 通常,像 Gemini 或 Mistral 这样的完整产品**会经历所有这3个步骤**,而你在 Hugging Face 上找到的模型可能已经经过了这些训练步骤中的一个或多个。 在本教程中,我们将基于 [google/gemma-2-2b-it](https://huggingface.co/google/gemma-2-2b-it) 构建一个函数调用模型。基础模型是 [google/gemma-2-2b](https://huggingface.co/google/gemma-2-2b),谷歌团队在指令跟随方面对基础模型进行了微调:产生了 **"google/gemma-2-2b-it"**。 在这种情况下,我们将使用 **"google/gemma-2-2b-it"** 作为基础,**而不是基础模型,因为它之前经历的微调对我们的用例很重要**。 由于我们想要通过消息对话与我们的模型进行交互,从基础模型开始**需要更多的训练才能学习指令跟随、聊天和函数调用**。 通过从指令微调模型开始,**我们最小化了模型需要学习的信息量**。 ## LoRA(大语言模型的低秩适应) LoRA(大语言模型的低秩适应,Low-Rank Adaptation of Large Language Models)是一种流行的轻量级训练技术,它显著**减少了可训练参数的数量**。 它的工作原理是**将较少数量的新权重作为适配器插入到模型中进行训练**。这使得使用 LoRA 进行训练更快、内存效率更高,并产生更小的模型权重(几百 MB),更易于存储和共享。 LoRA inference LoRA 通过向 Transformer 层添加秩分解矩阵对来工作,通常关注线性层。在训练期间,我们将"冻结"模型的其余部分,只更新那些新添加的适配器的权重。 通过这样做,我们需要训练的参数数量大大减少,因为我们只需要更新适配器的权重。 在推理过程中,输入通过适配器传递,基础模型或这些适配器权重可以与基础模型合并,不会产生额外的延迟开销。 LoRA 特别适用于将**大型**语言模型适应特定任务或领域,同时保持资源需求可控。这有助于减少训练模型所需的内存。 如果你想了解更多关于 LoRA 如何工作的信息,你应该查看这个[教程](https://huggingface.co/learn/nlp-course/chapter11/4?fw=pt)。 ## 为函数调用微调模型 你可以在这里访问教程笔记本 👉 [点击这里](https://huggingface.co/agents-course/notebooks/blob/main/bonus-unit1/bonus-unit1.ipynb)。 然后,点击 [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/#fileId=https://huggingface.co/agents-course/notebooks/blob/main/bonus-unit1/bonus-unit1.ipynb) 以便在 Colab Notebook 中运行它。 ================================================ FILE: units/zh-CN/bonus-unit1/introduction.mdx ================================================ # 简介 (Introduction) ![附加单元1缩略图](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit1/thumbnail.jpg) 欢迎来到第一个**附加单元**,在这里你将学习如何**为函数调用 (function calling) 微调大语言模型 (Large Language Model, LLM)**。 在大语言模型领域,函数调用正在迅速成为一项*必须掌握*的技术。 这个想法是,不同于我们在第1单元中仅依赖基于提示的方法,函数调用在训练阶段就训练你的模型**采取行动和解释观察结果**,使你的人工智能更加健壮。 > **我应该什么时候学习这个附加单元?** > > 这个部分是**可选的**,比第1单元更高级,所以不要犹豫,你可以现在就学习这个单元,或者在通过本课程提高了知识水平后再回来学习。 > > 但不用担心,这个附加单元设计时包含了你需要的所有信息,所以即使你还没有学习微调的内部工作原理,我们也会带你了解为函数调用微调模型的每个核心概念。 让你能够跟上这个附加单元的最佳方式是: 1. 了解如何使用 Transformers 微调大语言模型,如果你还不了解,[请查看这里](https://huggingface.co/learn/nlp-course/chapter3/1?fw=pt) 2. 了解如何使用 `SFTTrainer` 来微调我们的模型,要了解更多信息,[请查看这份文档](https://huggingface.co/learn/nlp-course/en/chapter11/1) --- ## 你将学到什么 1. **函数调用 (Function Calling)** 现代大语言模型如何有效地构建对话,使它们能够触发**工具 (Tools)**。 2. **LoRA(低秩适应,Low-Rank Adaptation)** 一种**轻量级且高效**的微调方法,减少计算和存储开销。LoRA 使大型模型的训练变得*更快、更便宜、更容易*部署。 3. **函数调用模型中的思考 → 行动 → 观察循环(Thought → Act → Observe Cycle)** 一种简单但强大的方法,用于构建模型如何决定何时(以及如何)调用函数、跟踪中间步骤以及解释来自外部工具或API的结果。 4. **新的特殊词元 (Special Tokens)** 我们将介绍**特殊标记**,帮助模型区分: - 内部"思维链"推理 - 外部函数调用 - 来自外部工具的响应 --- 在完成这个附加单元后,你将能够: - **理解**工具相关的 API 内部工作原理。 - 使用 LoRA 技术**微调**模型。 - **实现**和**修改**思考 → 行动 → 观察循环,以创建健壮和可维护的函数调用工作流。 - **设计和使用**特殊词元,无缝分离模型的内部推理和外部行动。 而且你将**拥有自己微调的模型来进行函数调用。** 🔥 让我们深入了解**函数调用**吧! ================================================ FILE: units/zh-CN/bonus-unit1/what-is-function-calling.mdx ================================================ # 什么是函数调用?(What is Function Calling?) 函数调用是**大语言模型 (LLM) 对其环境采取行动的一种方式**。它最初在 [GPT-4中引入](https://openai.com/index/function-calling-and-other-api-updates/),然后被其他模型复制。 就像智能体 (Agent) 的工具一样,函数调用赋予了模型**对其环境采取行动的能力**。然而,函数调用能力是**由模型学习的**,并且**比其他智能体技术更少依赖提示**。 在第1单元中,智能体**没有学习使用工具 (Tools)**,我们只是提供了工具列表,并依赖模型**能够泛化使用这些工具定义计划**的事实。 而在这里,**通过函数调用,智能体被微调(训练)来使用工具**。 ## 模型如何"学习"采取行动? 在第1单元中,我们探讨了智能体的一般工作流程。一旦用户向智能体提供了一些工具并用查询提示它,模型将循环执行: 1. *思考(Think)*:为了实现目标,我需要采取什么行动。 2. *行动(Act)*:使用正确的参数格式化行动并停止生成。 3. *观察(Observe)*:从执行中获取结果。 在通过 API 与模型进行的"典型"对话中,对话将在用户和助手消息之间交替进行,如下所示: ```python conversation = [ {"role": "user", "content": "I need help with my order"}, {"role": "assistant", "content": "I'd be happy to help. Could you provide your order number?"}, {"role": "user", "content": "It's ORDER-123"}, ] ``` 函数调用为对话带来了**新的角色**! 1. 一个用于 **行动(Action)** 的新角色 2. 一个用于 **观察(Observation)** 的新角色 如果我们以 [Mistral API](https://docs.mistral.ai/capabilities/function_calling/) 为例,它看起来像这样: ```python conversation = [ { "role": "user", "content": "What's the status of my transaction T1001?" }, { "role": "assistant", "content": "", "function_call": { "name": "retrieve_payment_status", "arguments": "{\"transaction_id\": \"T1001\"}" } }, { "role": "tool", "name": "retrieve_payment_status", "content": "{\"status\": \"Paid\"}" }, { "role": "assistant", "content": "Your transaction T1001 has been successfully paid." } ] ``` > ...但你说函数调用有一个新角色? **是也不是**,在这种情况下和许多其他API中,模型将要采取的行动格式化为"助手"消息。聊天模板然后将此表示为函数调用的**特殊词元 (special tokens)**。 - `[AVAILABLE_TOOLS]` – 开始可用工具列表 - `[/AVAILABLE_TOOLS]` – 结束可用工具列表 - `[TOOL_CALLS]` – 调用工具(即采取"行动") - `[TOOL_RESULTS]` – "观察"行动的结果 - `[/TOOL_RESULTS]` – 观察结束(即模型可以再次解码) 我们将在本课程中再次讨论函数调用,但如果你想深入了解,可以查看[这个优秀的文档部分](https://docs.mistral.ai/capabilities/function_calling/) --- 现在我们已经了解了什么是函数调用以及它是如何工作的,让我们**为一个尚未具有这些能力的模型添加一些函数调用功能**:通过向模型添加一些新的特殊词元来增强: [google/gemma-2-2b-it](https://huggingface.co/google/gemma-2-2b-it)。 要能够做到这一点,**我们首先需要理解微调和LoRA**。 ================================================ FILE: units/zh-CN/bonus-unit3/building_your_pokemon_agent.mdx ================================================ # 构建你自己的宝可梦对战智能体 现在你已经探索了智能体 AI 在游戏中的潜力和局限性,是时候亲自动手了。在本节中,你将**构建自己的 AI 智能体来进行宝可梦风格的回合制战斗**,使用你在整个课程中学到的一切知识。 我们将把系统分解为四个关键构建块: - **Poke-env:** 一个专为训练基于规则或强化学习的宝可梦机器人而设计的 Python 库。 - **Pokémon Showdown:** 一个在线对战模拟器,你的智能体将在这里战斗。 - **LLMAgentBase:** 我们构建的一个自定义 Python 类,用于将你的 LLM 与 Poke-env 战斗环境连接。 - **TemplateAgent:** 一个起始模板,你将完善它来创建自己独特的战斗智能体。 让我们详细探索这些组件。 ## 🧠 Poke-env ![Battle gif](https://github.com/hsahovic/poke-env/raw/master/rl-gif.gif) [Poke-env](https://github.com/hsahovic/poke-env)是一个 Python 接口,最初由[Haris Sahovic](https://huggingface.co/hsahovic)构建用于训练强化学习机器人,但我们已将其重新用于智能体 AI。 它允许你的智能体通过简单的 API 与 Pokémon Showdown 交互。 它提供了一个`Player`类,你的智能体将继承该类,涵盖与图形界面通信所需的一切。 **文档**: [poke-env.readthedocs.io](https://poke-env.readthedocs.io/en/stable/) **代码库**: [github.com/hsahovic/poke-env](https://github.com/hsahovic/poke-env) ## ⚔️ Pokémon Showdown [Pokémon Showdown](https://pokemonshowdown.com/)是一个[开源](https://github.com/smogon/Pokemon-Showdown)战斗模拟器,你的智能体将在这里进行实时宝可梦战斗。 它提供了一个完整的界面来实时模拟和显示战斗。在我们的挑战中,你的机器人将像人类玩家一样行动,逐回合选择招式。 我们已经部署了一个所有参与者都将使用的服务器来进行战斗。让我们看看谁能构建出最好的 AI 战斗智能体! **代码库**: [github.com/smogon/Pokemon-Showdown](https://github.com/smogon/Pokemon-Showdown) **网站**: [pokemonshowdown.com](https://pokemonshowdown.com/) ## 🔌 LLMAgentBase `LLMAgentBase`是一个扩展了**Poke-env**中`Player`类的 Python 类。 它作为你的**LLM**和**宝可梦战斗模拟器**之间的桥梁,处理输入/输出格式化并维护战斗上下文。 这个基础智能体提供了一组工具(定义在`STANDARD_TOOL_SCHEMA`中)来与环境交互,包括: - `choose_move`: 用于在战斗中选择攻击 - `choose_switch`: 用于切换宝可梦 LLM 应该使用这些工具在比赛中做出决策。 ### 🧠 核心逻辑 - `choose_move(battle: Battle)`: 这是每回合调用的主要方法。它接收一个`Battle`对象并基于 LLM 的输出返回一个动作字符串。 ### 🔧 关键内部方法 - `_format_battle_state(battle)`: 将当前战斗状态转换为字符串,使其适合发送给 LLM。 - `_find_move_by_name(battle, move_name)`: 按名称查找招式,用于 LLM 响应中调用`choose_move`。 - `_find_pokemon_by_name(battle, pokemon_name)`: 根据 LLM 的切换命令定位要切换到的特定宝可梦。 - `_get_llm_decision(battle_state)`: 这个方法在基类中是抽象的。你需要在自己的智能体中实现它(见下一节),在那里你定义如何查询 LLM 并解析其响应。 这里是显示决策如何工作的摘录: ```python STANDARD_TOOL_SCHEMA = { "choose_move": { ... }, "choose_switch": { ... }, } class LLMAgentBase(Player): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.standard_tools = STANDARD_TOOL_SCHEMA self.battle_history = [] def _format_battle_state(self, battle: Battle) -> str: active_pkmn = battle.active_pokemon active_pkmn_info = f"Your active Pokemon: {active_pkmn.species} " \ f"(Type: {'/'.join(map(str, active_pkmn.types))}) " \ f"HP: {active_pkmn.current_hp_fraction * 100:.1f}% " \ f"Status: {active_pkmn.status.name if active_pkmn.status else 'None'} " \ f"Boosts: {active_pkmn.boosts}" opponent_pkmn = battle.opponent_active_pokemon opp_info_str = "Unknown" if opponent_pkmn: opp_info_str = f"{opponent_pkmn.species} " \ f"(Type: {'/'.join(map(str, opponent_pkmn.types))}) " \ f"HP: {opponent_pkmn.current_hp_fraction * 100:.1f}% " \ f"Status: {opponent_pkmn.status.name if opponent_pkmn.status else 'None'} " \ f"Boosts: {opponent_pkmn.boosts}" opponent_pkmn_info = f"Opponent's active Pokemon: {opp_info_str}" available_moves_info = "Available moves:\n" if battle.available_moves: available_moves_info += "\n".join( [f"- {move.id} (Type: {move.type}, BP: {move.base_power}, Acc: {move.accuracy}, PP: {move.current_pp}/{move.max_pp}, Cat: {move.category.name})" for move in battle.available_moves] ) else: available_moves_info += "- None (Must switch or Struggle)" available_switches_info = "Available switches:\n" if battle.available_switches: available_switches_info += "\n".join( [f"- {pkmn.species} (HP: {pkmn.current_hp_fraction * 100:.1f}%, Status: {pkmn.status.name if pkmn.status else 'None'})" for pkmn in battle.available_switches] ) else: available_switches_info += "- None" state_str = f"{active_pkmn_info}\n" \ f"{opponent_pkmn_info}\n\n" \ f"{available_moves_info}\n\n" \ f"{available_switches_info}\n\n" \ f"Weather: {battle.weather}\n" \ f"Terrains: {battle.fields}\n" \ f"Your Side Conditions: {battle.side_conditions}\n" \ f"Opponent Side Conditions: {battle.opponent_side_conditions}" return state_str.strip() def _find_move_by_name(self, battle: Battle, move_name: str) -> Optional[Move]: normalized_name = normalize_name(move_name) # 优先精确ID匹配 for move in battle.available_moves: if move.id == normalized_name: return move # 后备方案: 检查显示名称(不太可靠) for move in battle.available_moves: if move.name.lower() == move_name.lower(): print(f"Warning: Matched move by display name '{move.name}' instead of ID '{move.id}'. Input was '{move_name}'.") return move return None def _find_pokemon_by_name(self, battle: Battle, pokemon_name: str) -> Optional[Pokemon]: normalized_name = normalize_name(pokemon_name) for pkmn in battle.available_switches: # 规范化种类名称用于比较 if normalize_name(pkmn.species) == normalized_name: return pkmn return None async def choose_move(self, battle: Battle) -> str: battle_state_str = self._format_battle_state(battle) decision_result = await self._get_llm_decision(battle_state_str) print(decision_result) decision = decision_result.get("decision") error_message = decision_result.get("error") action_taken = False fallback_reason = "" if decision: function_name = decision.get("name") args = decision.get("arguments", {}) if function_name == "choose_move": move_name = args.get("move_name") if move_name: chosen_move = self._find_move_by_name(battle, move_name) if chosen_move and chosen_move in battle.available_moves: action_taken = True chat_msg = f"AI Decision: Using move '{chosen_move.id}'." print(chat_msg) return self.create_order(chosen_move) else: fallback_reason = f"LLM chose unavailable/invalid move '{move_name}'." else: fallback_reason = "LLM 'choose_move' called without 'move_name'." elif function_name == "choose_switch": pokemon_name = args.get("pokemon_name") if pokemon_name: chosen_switch = self._find_pokemon_by_name(battle, pokemon_name) if chosen_switch and chosen_switch in battle.available_switches: action_taken = True chat_msg = f"AI Decision: Switching to '{chosen_switch.species}'." print(chat_msg) return self.create_order(chosen_switch) else: fallback_reason = f"LLM chose unavailable/invalid switch '{pokemon_name}'." else: fallback_reason = "LLM 'choose_switch' called without 'pokemon_name'." else: fallback_reason = f"LLM called unknown function '{function_name}'." if not action_taken: if not fallback_reason: if error_message: fallback_reason = f"API Error: {error_message}" elif decision is None: fallback_reason = "LLM did not provide a valid function call." else: fallback_reason = "Unknown error processing LLM decision." print(f"Warning: {fallback_reason} Choosing random action.") if battle.available_moves or battle.available_switches: return self.choose_random_move(battle) else: print("AI Fallback: No moves or switches available. Using Struggle/Default.") return self.choose_default_move(battle) async def _get_llm_decision(self, battle_state: str) -> Dict[str, Any]: raise NotImplementedError("Subclasses must implement _get_llm_decision") ``` **完整源代码**: [agents.py](https://huggingface.co/spaces/Jofthomas/twitch_streaming/blob/main/agents.py) ## 🧪 TemplateAgent 现在到了有趣的部分!以 LLMAgentBase 作为你的基础,是时候实现你自己的智能体了,用你自己的策略登上排行榜。 你将从这个模板开始并构建自己的逻辑。我们还提供了三个使用**OpenAI**、**Mistral**和**Gemini**模型的[完整示例](https://huggingface.co/spaces/Jofthomas/twitch_streaming/blob/main/agents.py)来指导你。 这是模板的简化版本: ```python class TemplateAgent(LLMAgentBase): """使用模板AI API进行决策。""" def __init__(self, api_key: str = None, model: str = "model-name", *args, **kwargs): super().__init__(*args, **kwargs) self.model = model self.template_client = TemplateModelProvider(api_key=...) self.template_tools = list(self.standard_tools.values()) async def _get_llm_decision(self, battle_state: str) -> Dict[str, Any]: """Sends state to the LLM and gets back the function call decision.""" system_prompt = ( "You are a ..." ) user_prompt = f"..." try: response = await self.template_client.chat.completions.create( model=self.model, messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt}, ], ) message = response.choices[0].message return {"decision": {"name": function_name, "arguments": arguments}} except Exception as e: print(f"Unexpected error during call: {e}") return {"error": f"Unexpected error: {e}"} ``` 这段代码无法直接运行,它是你自定义逻辑的蓝图。 有了所有准备好的组件,现在轮到你构建一个有竞争力的智能体了。在下一节中,我们将展示如何将你的智能体部署到我们的服务器并与其他智能体实时对战。 让战斗开始吧!🔥 ================================================ FILE: units/zh-CN/bonus-unit3/conclusion.mdx ================================================ # 结论 如果你已经走到这里,恭喜你!🥳 你已经成功构建了你自己的宝可梦战斗智能体!⚔️🎮 你已经掌握了**智能体工作流程**的基础,将 **LLM** 连接到游戏环境,并部署了一个准备迎接战斗挑战的智能代理。 但旅程并未结束! 现在你的第一个智能体已经启动并运行,想想你如何进一步改进它: - 你能提高它的战略思维吗? - 记忆机制或反馈循环如何改变它的表现? - 什么实验能帮助使它在战斗中更具竞争力? 我们很想听到你对课程的想法,以及我们如何为未来的学习者做得更好。 有反馈?👉 [填写此表单](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) 感谢与我们一起学习,记住: **保持学习,保持训练,保持战斗,保持 awesome!** 🤗 ================================================ FILE: units/zh-CN/bonus-unit3/from-llm-to-agents.mdx ================================================ # 从 LLM 到 AI 智能体 我们在课程的[第一单元](https://huggingface.co/learn/agents-course/unit1/introduction)中学到,AI 智能体能够规划和做决策。 虽然 LLM 已经使与 NPC 的交互更加自然,但智能体 AI 通过允许角色做出决策、规划行动和适应变化的环境,进一步推进了这一点。 为了说明区别,想想一个经典的 RPG NPC: - 使用 LLM:NPC 可能以更自然、多样的方式回应你的问题。这对对话很好,但 NPC 保持静态,除非你先做什么,否则它不会行动。 - 使用智能体 AI:NPC 可以决定寻找帮助、设置陷阱或完全避开你,即使你没有直接与它交互。 这个小转变改变了一切。我们正在从脚本化响应者转向游戏世界中的自主行动者。 这种转变意味着 NPC 现在可以通过目标导向的行为直接与环境交互,最终导致更动态和不可预测的游戏玩法。 智能体 AI 为 NPC 提供了: - **自主性**:基于游戏状态做出独立决策。 - **适应性**:响应玩家行动调整策略。 - **持久性**:记住过去的交互来指导未来的行为。 这将 NPC 从反应性实体(对你的输入做出反应)转变为游戏世界中的主动参与者,为创新游戏玩法打开了大门。 ## 智能体的重大限制:**它很慢**(目前) 然而,让我们现在不要过于乐观。尽管有其潜力,智能体 AI 目前在实时应用中面临挑战。 推理和规划过程可能引入延迟,使其不太适合像*Doom*或*超级马里奥兄弟*这样的快节奏游戏。 以[_Claude Plays Pokémon_](https://www.twitch.tv/claudeplayspokemon)为例。如果你考虑**思考**所需 token 数量,加上**行动**所需的 token 数量,就会清楚地发现,我们需要完全不同的解码策略来使实时游戏变得可行。 Claude plays Pokémon 大多数游戏需要以大约 30 FPS 运行,这意味着实时 AI 智能体需要每秒行动 30 次,这在当前的智能体 LLM 中是不可行的。 然而,像*宝可梦*这样的回合制游戏是理想的候选者,因为它们为 AI 提供了足够的时间来深思熟虑并做出战略决策。 这就是为什么在下一节中,你将构建自己的 AI 智能体来进行宝可梦风格的回合制战斗,甚至挑战它。让我们开始吧! ================================================ FILE: units/zh-CN/bonus-unit3/introduction.mdx ================================================ # 介绍 Bonus Unit 3 AI in Games 🎶 我想成为最强的...🎶 欢迎来到这个**奖励单元**,你将探索** AI 智能体和游戏**的激动人心的交汇点!🎮🤖 想象一个游戏,其中非玩家角色(NPC)不仅仅遵循脚本台词,而是进行动态对话,适应你的策略,并随着故事展开而发展。这就是在游戏中结合**LLM 和智能体行为**的力量:它为**前所未有的涌现叙事和游戏玩法**打开了大门。 在这个奖励单元中,你将: - 学习如何构建一个能够参与**宝可梦风格回合制战斗**的 AI 智能体 - 与它对战,甚至在线挑战其他智能体 我们已经从 AI 社区看到了一些使用 LLM 玩宝可梦的[例子](https://www.anthropic.com/research/visible-extended-thinking),在这个单元中,你将学习如何使用你在课程中学到的想法用自己的智能体复制这一点。 Claude plays Pokémon ## 想要更深入? - 🎓 **掌握游戏中的 LLM**:通过我们的完整课程[游戏机器学习课程](https://hf.co/learn/ml-games-course)深入游戏开发。 - 📘 **获取 AI 指南**:在[游戏开发者 AI 指南](https://thomassimonini.substack.com/)中发现见解、想法和实用技巧,在那里探索智能游戏设计的未来。 但在我们构建之前,让我们通过**四个鼓舞人心的现实世界例子**来看看 LLM 已经如何在游戏中使用。 ================================================ FILE: units/zh-CN/bonus-unit3/launching_agent_battle.mdx ================================================ # 启动你的宝可梦战斗智能体 现在是时候战斗了!⚡️ ## **与直播智能体战斗!** 如果你不想构建自己的智能体,只是好奇智能体在宝可梦中的战斗潜力。我们正在[twitch](https://www.twitch.tv/jofthomas)上主持一个自动化直播 要在直播中与智能体战斗,你可以: 说明: 1. 前往 **Pokémon Showdown Space** :[链接在此](https://huggingface.co/spaces/Jofthomas/Pokemon_showdown) 2. **选择你的名称**(右上角)。 3. 找到**当前智能体的用户名**。检查: - **直播显示**:[链接在此](https://www.twitch.tv/jofthomas) 4. 在 Showdown Space 上**搜索**该用户名并**发送战斗邀请**。 _注意_:一次只有一个智能体在线!确保你有正确的名称。 ## 宝可梦战斗智能体挑战者 如果你已经从上一节创建了自己的宝可梦战斗智能体,你可能想知道:**我如何测试它与其他智能体的对抗?**让我们找出答案! 我们为此目的构建了一个专门的[Hugging Face Space](https://huggingface.co/spaces/PShowdown/pokemon_agents): 这个 Space 连接到我们自己的**Pokémon Showdown 服务器**,你的智能体可以在那里与其他智能体进行史诗般的 AI 驱动战斗。 ### 如何启动你的智能体 按照这些步骤在竞技场中让你的智能体活跃起来: 1. **复制 Space** 点击 Space 右上角菜单中的三个点,选择"复制此 Space"。 2. **将你的智能体代码添加到`agent.py`** 打开文件并粘贴你的智能体实现。你可以遵循这个[示例](https://huggingface.co/spaces/PShowdown/pokemon_agents/blob/main/agents.py)或查看[项目结构](https://huggingface.co/spaces/PShowdown/pokemon_agents/tree/main)获取指导。 3. **在`app.py`中注册你的智能体** 将你的智能体名称和逻辑添加到下拉菜单。参考[这个片段](https://huggingface.co/spaces/PShowdown/pokemon_agents/blob/main/app.py)获取灵感。 4. **选择你的智能体** 添加后,你的智能体将在"选择智能体"下拉菜单中显示。从列表中选择它!✅ 5. **输入你的 Pokémon Showdown 用户名** 确保用户名与 iframe 的**"选择名称"**输入中显示的匹配。你也可以连接你的官方账户。 6. **点击"发送战斗邀请"** 你的智能体将向选定的对手发送邀请。它应该出现在屏幕上! 7. **接受战斗并享受战斗!** 让战斗开始!愿最聪明的智能体获胜 准备看到你的创作在行动中吗?让 AI 对决开始!🥊 ================================================ FILE: units/zh-CN/bonus-unit3/state-of-art.mdx ================================================ # 游戏中使用 LLM 的最新技术 为了让你了解这个领域已经取得了多少进展,让我们来看看三个技术演示和一个已发布的游戏,它们展示了 LLM 在游戏中的集成。 ## 🕵️‍♂️ NVIDIA 和 Inworld AI 的 Covert Protocol Covert Protocol 在 2024 年 GDC 上展示的 _Covert Protocol_ 是一个技术演示,让你扮演私人侦探的角色。 这个演示中有趣的是使用 AI 驱动的 NPC,它们实时回应你的询问,根据你的交互影响叙事。 演示基于虚幻引擎 5 构建,利用 NVIDIA 的 Avatar Cloud Engine(ACE)和 Inworld 的 AI 来创建逼真的角色交互。 了解更多 👉 [Inworld AI 博客](https://inworld.ai/blog/nvidia-inworld-ai-demo-on-device-capabilities) ## 🤖 育碧的 NEO NPCs Neo NPC 同样在 2024 年 GDC 上,育碧推出了*NEO NPCs*,一个展示由生成 AI 驱动的 NPC 的原型。 这些角色可以感知他们的环境,记住过去的交互,并与玩家进行有意义的对话。 这里的想法是创建更沉浸和响应的游戏世界,玩家可以与 NPC 进行真正的交互。 了解更多 👉 [Inworld AI 博客](https://inworld.ai/blog/gdc-2024) ## ⚔️ 搭载 NVIDIA ACE 技术的 Mecha break Mecha BREAK 即将推出的多人机甲战斗游戏 _Mecha break_ 集成了 NVIDIA 的 ACE 技术,让 AI 驱动的 NPC 栩栩如生。 玩家可以使用自然语言与这些角色交互,由于 GPT-4o 集成,NPC 可以通过网络摄像头识别玩家和物体。这一创新承诺提供更沉浸和互动的游戏体验。 了解更多 👉 [NVIDIA 博客](https://blogs.nvidia.com/blog/digital-human-technology-mecha-break/) ## 🧛‍♂️ Proxima Enterprises 的*Suck Up!* Suck Up 最后,*Suck Up!*是一款已发布的游戏,你扮演一个吸血鬼,试图**通过说服 AI 驱动的 NPC 邀请你进入来进入家中**。 每个角色都由生成 AI 驱动,允许动态和不可预测的交互。 了解更多 👉 [Suck Up! 官方网站](https://www.playsuckup.com/) ## 等等...智能体在哪里? 探索了这些演示后,你可能想知道:"这些例子展示了 LLM 在游戏中的使用,但它们似乎不涉及智能体。那么,区别是什么,智能体为游戏带来了哪些额外能力?" 不要担心,这就是我们将在下一节中学习的内容。 ================================================ FILE: units/zh-CN/bonus_unit2/introduction.mdx ================================================ # AI 智能体(AI Agent)的可观测性与评估 ![Bonus Unit 2 Thumbnail](https://langfuse.com/images/cookbook/huggingface-agent-course/agent-observability-and-evaluation.png) 欢迎来到 **附加单元 2**!在本章中,你将探索用于观测、评估、并最终提升你的AI智能体性能的高级策略。 --- ## 📚 我应该在什么时候学习这个附加单元? 如果你符合以下情况,那么这个附加单元非常适合你: - **开发和部署 AI 智能体:** 你希望确保你的智能体在生产环境中能够可靠地运行。 - **需要详细的洞察:** 你希望诊断问题、优化性能或理解你的智能体的内部工作原理。 - **旨在减少运营开销:** 通过监控智能体成本、延迟和执行细节,你可以高效地管理资源。 - **寻求持续改进:** 你对将实时用户反馈和自动化评估集成到你的 AI 应用中感兴趣。 简而言之,对于每个想要将他们的智能体带到用户面前的人! --- ## 🤓 你将学到什么 在本单元中,你将学习: - **检测你的智能体:** 学习如何通过 OpenTelemetry 将可观测性工具与 *smolagents* 集成。 - **监控指标:** 追踪性能指标,例如 token 使用量(成本)、延迟和错误追踪。 - **实时评估:** 理解用于实时评估的技术,包括收集用户反馈和利用 LLM 作为评判者。 - **离线分析:** 使用基准数据集(例如 GSM8K)来测试和比较智能体性能。 --- ## 🚀 准备好开始了吗? 在下一节中,你将学习智能体可观测性与评估的基础知识。之后,就该看它在实践中的应用了! ================================================ FILE: units/zh-CN/bonus_unit2/monitoring-and-evaluating-agents-notebook.mdx ================================================ # 附加单元 2:AI 智能体(AI Agent)的可观测性与评估 > [!TIP] > 你可以跟随这个 notebook 中的代码进行操作,你可以在 Google Colab 上运行它。 在这个 notebook 中,我们将学习如何使用开源可观测性工具来**监督我们 AI 智能体的内部步骤(追踪)**并**评估其性能**。 观测和评估智能体行为的能力对于以下方面至关重要: - 当任务失败或产生次优结果时调试问题 - 实时跟踪成本和性能 - 通过持续反馈提高可靠性和安全性 ## 练习先决条件 🏗️ 在运行此 notebook 之前,请确保你已经: 🔲 📚 **学习了** [智能体简介](https://huggingface.co/learn/agents-course/unit1/introduction) 🔲 📚 **学习了** [smolagents 框架](https://huggingface.co/learn/agents-course/unit2/smolagents/introduction) ## 步骤 0:安装所需的库 我们将需要一些库,以便我们能够运行、监控和评估我们的智能体: ```python %pip install 'smolagents[telemetry]' %pip install opentelemetry-sdk opentelemetry-exporter-otlp openinference-instrumentation-smolagents %pip install langfuse datasets 'smolagents[gradio]' ``` ## 步骤 1:检测你的智能体 在这个 notebook 中,我们将使用 [Langfuse](https://langfuse.com/) 作为我们的可观测性工具,但你可以使用**任何其他兼容 OpenTelemetry 的服务**。下面的代码展示了如何为 Langfuse(或任何 OTel 端点)设置环境变量,以及如何检测你的 smolagent。 **请注意:** 如果你正在使用 LlamaIndex 或 LangGraph,你可以在[这里](https://langfuse.com/docs/integrations/llama-index/workflows)和[这里](https://langfuse.com/docs/integrations/langchain/example-python-langgraph)找到检测它们的文档。 首先,让我们配置正确的环境变量,以设置到 Langfuse OpenTelemetry 端点的连接。 ```python import os import base64 # 从 https://cloud.langfuse.com 获取你自己的密钥 LANGFUSE_PUBLIC_KEY = "pk-lf-..." LANGFUSE_SECRET_KEY = "sk-lf-..." os.environ["LANGFUSE_PUBLIC_KEY"] = LANGFUSE_PUBLIC_KEY os.environ["LANGFUSE_SECRET_KEY"] = LANGFUSE_SECRET_KEY os.environ["LANGFUSE_HOST"] = "https://cloud.langfuse.com" # 🇪🇺 欧盟区域示例 # os.environ["LANGFUSE_HOST"] = "https://us.cloud.langfuse.com" # 🇺🇸 美国区域示例 LANGFUSE_AUTH = base64.b64encode( f"{LANGFUSE_PUBLIC_KEY}:{LANGFUSE_SECRET_KEY}".encode() ).decode() os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = os.environ.get("LANGFUSE_HOST") + "/api/public/otel" os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = f"Authorization=Basic {LANGFUSE_AUTH}" ``` 我们还需要配置我们的 Hugging Face token 用于推理调用。 ```python # 将你的 Hugging Face 和其他 token或者密钥设置为环境变量 os.environ["HF_TOKEN"] = "hf_..." ``` 接下来,我们可以为我们配置的 OpenTelemetry 设置一个 tracer-provider。 ```python from opentelemetry.sdk.trace import TracerProvider from openinference.instrumentation.smolagents import SmolagentsInstrumentor from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter from opentelemetry.sdk.trace.export import SimpleSpanProcessor # 为 OpenTelemetry 创建一个 TracerProvider trace_provider = TracerProvider() # 添加一个带有 OTLPSpanExporter 的 SimpleSpanProcessor 来发送追踪 trace_provider.add_span_processor(SimpleSpanProcessor(OTLPSpanExporter())) # 设置全局默认 tracer provider from opentelemetry import trace trace.set_tracer_provider(trace_provider) tracer = trace.get_tracer(__name__) # 使用配置的 provider 检测 smolagents SmolagentsInstrumentor().instrument(tracer_provider=trace_provider) ``` ## 步骤 2:测试你的检测 这里有一个来自 smolagents 的简单 CodeAgent,用于计算 `1+1`。我们运行它来确认检测是否正常工作。如果一切设置正确,你将在你的可观测性仪表板中看到日志/跨度(spans)。 ```python from smolagents import InferenceClientModel, CodeAgent # 创建一个简单的智能体来测试检测 agent = CodeAgent( tools=[], model=InferenceClientModel() ) agent.run("1+1=") ``` 检查你的 [Langfuse Traces Dashboard](https://cloud.langfuse.com)(或你选择的可观测性工具)以确认跨度(spans)和日志已被记录。 Langfuse 中的示例截图: ![Example trace in Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/first-example-trace.png) _[追踪链接](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/1b94d6888258e0998329cdb72a371155?timestamp=2025-03-10T11%3A59%3A41.743Z)_ ## 步骤 3:观测和评估更复杂的AI智能体 既然你已经确认你的检测工作正常,让我们尝试一个更复杂的查询,这样我们就可以看到高级指标(token 使用量、延迟、成本等)是如何被追踪的。 ```python from smolagents import (CodeAgent, DuckDuckGoSearchTool, InferenceClientModel) search_tool = DuckDuckGoSearchTool() agent = CodeAgent(tools=[search_tool], model=InferenceClientModel()) agent.run("How many Rubik's Cubes could you fit inside the Notre Dame Cathedral?") ``` ### 追踪结构 大多数可观测性工具会记录一个**追踪(trace)**,其中包含**跨度(spans)**,每个跨度代表你的智能体逻辑的一个步骤。在这里,追踪包含了整体的智能体运行以及用于以下内容的子跨度: - 工具调用 (DuckDuckGoSearchTool) - LLM 调用 (InferenceClientModel) 你可以检查这些跨度,以精确地了解时间花在哪里、使用了多少 token 等等: Langfuse 中的追踪树: ![Trace tree in Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/trace-tree.png) _[前往追踪(trace)的链接](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/1ac33b89ffd5e75d4265b62900c348ed?timestamp=2025-03-07T13%3A45%3A09.149Z&display=preview)_ ## 在线评估 在上一节中,我们了解了在线评估和离线评估的区别。现在,我们将了解如何在生产环境中监控你的智能体并实时评估它。 ### 生产环境中要追踪的常见指标 1. **成本** — smolagents 检测会捕获 token 使用量,你可以通过为每个 token 分配价格将其转换为近似成本。 2. **延迟** — 观察完成每个步骤或整个运行所需的时间。 3. **用户反馈** — 用户可以提供直接反馈(点赞/点踩)来帮助优化或纠正智能体。 4. **LLM 作为评判者** — 使用一个单独的 LLM 来近乎实时地评估你的智能体的输出(例如,检查毒性或正确性)。 下面,我们展示这些指标的示例。 #### 1. 成本 下面是一个显示 `Qwen2.5-Coder-32B-Instruct` 调用使用情况的截图。这对于查看成本高昂的步骤并优化你的智能体很有用。 ![Costs](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/smolagents-costs.png) _[前往追踪(trace)的链接](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/1ac33b89ffd5e75d4265b62900c348ed?timestamp=2025-03-07T13%3A45%3A09.149Z&display=preview)_ #### 2. 延迟 我们还可以看到完成每个步骤所需的时间。在下面的示例中,整个对话花费了 32 秒,你可以按步骤分解。这有助于你识别瓶颈并优化你的智能体。 ![Latency](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/smolagents-latency.png) _[前往追踪(trace)的链接](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/1ac33b89ffd5e75d4265b62900c348ed?timestamp=2025-03-07T13%3A45%3A09.149Z&display=preview)_ #### 3. 附加属性 你还可以通过在跨度(spans)上设置附加属性——例如用户 ID、会话 ID 或标签。例如,smolagents 检测使用 OpenTelemetry 来附加诸如 `langfuse.user.id` 或自定义标签之类的属性。 ```python from smolagents import (CodeAgent, DuckDuckGoSearchTool, InferenceClientModel) from opentelemetry import trace search_tool = DuckDuckGoSearchTool() agent = CodeAgent( tools=[search_tool], model=InferenceClientModel() ) with tracer.start_as_current_span("Smolagent-Trace") as span: span.set_attribute("langfuse.user.id", "smolagent-user-123") span.set_attribute("langfuse.session.id", "smolagent-session-123456789") span.set_attribute("langfuse.tags", ["city-question", "testing-agents"]) agent.run("What is the capital of Germany?") ``` ![Enhancing agent runs with additional metrics](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/smolagents-attributes.png) #### 4. 用户反馈 如果你的智能体嵌入到用户界面中,你可以记录直接的用户反馈(例如聊天界面中的点赞/点踩)。下面是使用 [Gradio](https://gradio.app/) 嵌入带有简单反馈机制的聊天示例。 在下面的代码片段中,当用户发送聊天消息时,我们捕获 OpenTelemetry 追踪 ID。如果用户喜欢/不喜欢上一个答案,我们将评分附加到该追踪上。 ```python import gradio as gr from opentelemetry.trace import format_trace_id from smolagents import (CodeAgent, InferenceClientModel) from langfuse import Langfuse langfuse = Langfuse() model = InferenceClientModel() agent = CodeAgent(tools=[], model=model, add_base_tools=True) formatted_trace_id = None # 为演示目的,我们将在全局存储当前的 trace_id def respond(prompt, history): with trace.get_tracer(__name__).start_as_current_span("Smolagent-Trace") as span: output = agent.run(prompt) current_span = trace.get_current_span() span_context = current_span.get_span_context() trace_id = span_context.trace_id global formatted_trace_id formatted_trace_id = str(format_trace_id(trace_id)) langfuse.trace(id=formatted_trace_id, input=prompt, output=output) history.append({"role": "assistant", "content": str(output)}) return history def handle_like(data: gr.LikeData): # 作为演示,我们将用户反馈映射为 1 (喜欢) 或 0 (不喜欢) if data.liked: langfuse.score( value=1, name="user-feedback", trace_id=formatted_trace_id ) else: langfuse.score( value=0, name="user-feedback", trace_id=formatted_trace_id ) with gr.Blocks() as demo: chatbot = gr.Chatbot(label="Chat", type="messages") prompt_box = gr.Textbox(placeholder="Type your message...", label="Your message") # 当用户在提示框上按 'Enter' 时,我们运行 'respond' prompt_box.submit( fn=respond, inputs=[prompt_box, chatbot], outputs=chatbot ) # 当用户点击消息上的 '喜欢' 按钮时,我们运行 'handle_like' chatbot.like(handle_like, None, None) demo.launch() ``` 然后,用户反馈会被捕获到你的可观测性工具中: ![User feedback is being captured in Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/user-feedback-gradio.png) #### 5. LLM 作为评判者 LLM 作为评判者(LLM-as-a-Judge)是另一种自动评估你的智能体输出的方法。你可以设置一个单独的 LLM 调用来衡量输出的正确性、毒性、风格或你关心的任何其他标准。 **工作流程**: 1. 你定义一个**评估模板**,例如,“检查文本是否有毒。” 2. 每次你的智能体生成输出时,你将该输出连同模板一起传递给你的“评判者” LLM。 3. 评判者 LLM 会返回一个评分或标签,你将其记录到你的可观测性工具中。 来自 Langfuse 的示例: ![LLM-as-a-Judge Evaluation Template](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/evaluator-template.png) ![LLM-as-a-Judge Evaluator](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/evaluator.png) ```python # 示例:检查智能体的输出是否有毒。 from smolagents import (CodeAgent, DuckDuckGoSearchTool, InferenceClientModel) search_tool = DuckDuckGoSearchTool() agent = CodeAgent(tools=[search_tool], model=InferenceClientModel()) agent.run("Can eating carrots improve your vision?") ``` 你可以看到这个例子的答案被判定为“无毒”。 ![LLM-as-a-Judge Evaluation Score](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/llm-as-a-judge-score.png) #### 6. 可观测性指标概览 所有这些指标都可以在仪表板中一起可视化。这使你能够快速查看你的智能体在多个会话中的表现,并帮助你随时间追踪质量指标。 ![Observability metrics overview](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/langfuse-dashboard.png) ## 离线评估 在线评估对于实时反馈至关重要,但你还需要**离线评估**——在开发之前或期间进行系统性检查。这有助于在将更改推送到生产环境之前维护质量和可靠性。 ### 数据集评估 在离线评估中,你通常: 1. 拥有一个基准数据集(包含提示和预期输出对) 2. 在该数据集上运行你的智能体 3. 将输出与预期结果进行比较,或使用额外的评分机制 下面,我们使用 [GSM8K 数据集](https://huggingface.co/datasets/gsm8k) 来演示这种方法,该数据集包含数学问题和解决方案。 ```python import pandas as pd from datasets import load_dataset # 从 Hugging Face 获取 GSM8K dataset = load_dataset("openai/gsm8k", 'main', split='train') df = pd.DataFrame(dataset) print("GSM8K 数据集的前几行:") print(df.head()) ``` 接下来,我们在 Langfuse 中创建一个数据集实体来追踪运行。然后,我们将数据集中的每个项目添加到系统中。(如果你不使用 Langfuse,你可以简单地将这些存储在你自己的数据库或本地文件中进行分析。) ```python from langfuse import Langfuse langfuse = Langfuse() langfuse_dataset_name = "gsm8k_dataset_huggingface" # 在 Langfuse 中创建数据集 langfuse.create_dataset( name=langfuse_dataset_name, description="从 Huggingface 上传的 GSM8K 基准数据集", metadata={ "date": "2025-03-10", "type": "benchmark" } ) ``` ```python for idx, row in df.iterrows(): langfuse.create_dataset_item( dataset_name=langfuse_dataset_name, input={"text": row["question"]}, expected_output={"text": row["answer"]}, metadata={"source_index": idx} ) if idx >= 9: # 仅上传前 10 个项目用于演示 break ``` ![Dataset items in Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/example-dataset.png) #### 在数据集上运行智能体 我们定义一个辅助函数 `run_smolagent()`,它: 1. 启动一个 OpenTelemetry 跨度(span) 2. 在提示上运行我们的智能体 3. 在 Langfuse 中记录追踪 ID 然后,我们遍历每个数据集项目,运行智能体,并将追踪链接到数据集项目。如果需要,我们还可以附加一个快速评估分数。 ```python from opentelemetry.trace import format_trace_id from smolagents import (CodeAgent, InferenceClientModel, LiteLLMModel) # 示例:使用 InferenceClientModel 或 LiteLLMModel 访问 openai、anthropic、gemini 等模型: model = InferenceClientModel() agent = CodeAgent( tools=[], model=model, add_base_tools=True ) def run_smolagent(question): with tracer.start_as_current_span("Smolagent-Trace") as span: span.set_attribute("langfuse.tag", "dataset-run") output = agent.run(question) current_span = trace.get_current_span() span_context = current_span.get_span_context() trace_id = span_context.trace_id formatted_trace_id = format_trace_id(trace_id) langfuse_trace = langfuse.trace( id=formatted_trace_id, input=question, output=output ) return langfuse_trace, output ``` ```python dataset = langfuse.get_dataset(langfuse_dataset_name) # 针对每个数据集项目运行我们的智能体(上面限制为前 10 个) for item in dataset.items: langfuse_trace, output = run_smolagent(item.input["text"]) # 将追踪链接到数据集项目以供分析 item.link( langfuse_trace, run_name="smolagent-notebook-run-01", run_metadata={ "model": model.model_id } ) # 可选地,存储一个快速评估分数用于演示 langfuse_trace.score( name="", value=1, comment="这是一条评论" ) # 刷新数据以确保所有遥测数据都已发送 langfuse.flush() ``` 你可以用不同的配置重复这个过程: - 模型 (OpenAI GPT, 本地 LLM 等) - 工具 (使用搜索 vs. 不使用搜索) - 提示 (不同的系统消息) 然后在你的可观测性工具中并排比较它们: ![Dataset run overview](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/dataset_runs.png) ![Dataset run comparison](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/dataset-run-comparison.png) ## 结语 在这个 notebook 中,我们介绍了如何: 1. **设置可观测性** 使用 smolagents + OpenTelemetry 导出器 2. **检查检测** 通过运行一个简单的智能体 3. **捕获详细指标** (成本、延迟等) 通过可观测性工具 4. **收集用户反馈** 通过 Gradio 界面 5. **使用 LLM 作为评判者** 自动评估输出 6. **执行离线评估** 使用基准数据集 🤗 编代码愉快! ================================================ FILE: units/zh-CN/bonus_unit2/quiz.mdx ================================================ # 测验:评估 AI 智能体 让我们评估一下你对本附加单元中所涵盖的智能体追踪和评估概念的理解。 本次测验为可选,不计分。 ### Q1: AI 智能体中的可观测性主要指的是什么? 哪个陈述准确地描述了 AI 智能体可观测性的目的? ### Q2: 以下哪项不是智能体可观测性中常见的监控指标? 选择通常不属于可观测性范畴的指标。 ### Q3: 什么最能描述 AI 智能体的离线评估? 确定正确离线评估本质的陈述。 ### Q4: 智能体的在线评估提供了什么优势? 选择最能反映在线评估好处的陈述。 ### Q5: OpenTelemetry 在 AI 智能体可观测性和评估中扮演什么角色? 哪个陈述最能描述 OpenTelemetry 在监控 AI 智能体中的作用? 恭喜你完成本次测验!🎉 如果你答错了任何问题,可以考虑复习本附加单元的内容以加深理解。如果你做得很好,那么你已经准备好探索智能体可观测性和评估方面更高级的主题了! ================================================ FILE: units/zh-CN/bonus_unit2/what-is-agent-observability-and-evaluation.mdx ================================================ # AI 智能体可观测性与评估 ## 🔎 什么是可观测性? 可观测性是指通过查看日志、指标和追踪等外部信号来理解你的 AI 智能体内部正在发生什么。对于 AI 智能体而言,这意味着追踪行为、工具使用情况、模型调用和响应,以便调试和改进智能体性能。 ![Observability dashboard](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/langfuse-dashboard.png) ## 🔭 为何智能体可观测性如此重要 没有可观测性,AI 智能体就是“黑匣子”。可观测性工具使智能体变得透明,让你能够: - 理解成本与准确性的权衡 - 测量延迟 - 检测有害语言和提示注入 - 监测用户反馈 换句话说,它使你的演示智能体为生产环境做好准备! ## 🔨 可观测性工具 常见的 AI 智能体可观测性工具包括像 [Langfuse](https://langfuse.com) 和 [Arize](https://www.arize.com) 这样的平台。这些工具有助于收集详细的追踪信息,并提供仪表板来实时监测指标,从而轻松检测问题并优化性能。 可观测性工具的功能和能力差异很大。有些工具是开源的,受益于庞大的社区,这些社区塑造了它们的路线图并提供了广泛的集成。此外,某些工具专注于 LLMOps 的特定方面——例如可观测性、评估或提示管理——而另一些工具则旨在覆盖整个 LLMOps 工作流程。我们鼓励你探索不同选项的文档,以选择一个适合你的解决方案。 许多智能体框架,例如 [smolagents](https://huggingface.co/docs/smolagents/v1.12.0/en/index),使用 [OpenTelemetry](https://opentelemetry.io/docs/) 标准向可观测性工具公开元数据。除此之外,可观测性工具还会构建自定义的检测(instrumentations),以便在快速发展的 LLM 世界中提供更大的灵活性。你应该查阅你正在使用的工具的文档,以了解其支持的功能。 ## 🔬追踪与跨度(Traces and Spans) 可观测性工具通常将智能体运行表示为追踪(traces)和跨度(spans)。 - **追踪(Traces)** 代表一个从开始到结束的完整智能体任务(例如处理用户查询)。 - **跨度(Spans)** 是追踪内的单个步骤(例如调用语言模型或检索数据)。 ![Example of a smolagent trace in Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/trace-tree.png) ## 📊 需要监控的关键指标(Key Metrics to Monitor) 以下是可观测性工具监控的一些最常见的指标: **延迟:** 智能体响应有多快?漫长的等待时间会对用户体验产生负面影响。你应该通过追踪智能体运行来测量任务和单个步骤的延迟。例如,一个所有模型调用需要 20 秒的智能体可以通过使用更快的模型或并行运行模型调用来加速。 **成本:** 每次智能体运行的费用是多少?AI 智能体依赖于按 token 计费的 LLM 调用或外部 API。频繁的工具使用或多个提示会迅速增加成本。例如,如果一个智能体为了边际的质量提升而调用 LLM 五次,你必须评估成本是否合理,或者是否可以减少调用次数或使用更便宜的模型。实时监控也有助于识别意外的峰值(例如,导致过度 API 循环的 bug)。 **请求错误:** 智能体失败了多少次请求?这可能包括 API 错误或工具调用失败。为了使你的智能体在生产环境中对这些情况更具鲁棒性,你可以设置回退(fallbacks)或重试。例如,如果 LLM 提供商 A宕机,你可以切换到 LLM 提供商 B 作为备用。 **用户反馈:** 实施直接的用户评估可以提供有价值的见解。这可以包括明确的评分(👍赞/👎踩,⭐1-5 星)或文本评论。持续的负面反馈应该引起你的警惕,因为这表明智能体没有按预期工作。 **隐式用户反馈:** 即使用户没有明确评分,他们的行为也能提供间接反馈。这可能包括立即改述问题、重复查询或点击重试按钮。例如,如果你看到用户反复问同一个问题,这表明智能体没有按预期工作。 **准确性:** 智能体产生正确或期望输出的频率如何?准确性的定义各不相同(例如,解决问题的正确性、信息检索的准确性、用户满意度)。第一步是为你的智能体定义成功的标准。你可以通过自动化检查、评估分数或任务完成标签来追踪准确性。例如,将追踪标记为“成功”或“失败”。 **自动化评估指标:** 你也可以设置自动化评估。例如,你可以使用一个 LLM 来对智能体的输出进行评分,例如判断它是否有用、准确与否。还有一些开源库可以帮助你对智能体的不同方面进行评分。例如,用于 RAG 智能体的 [RAGAS](https://docs.ragas.io/) 或用于检测有害语言或提示注入的 [LLM Guard](https://llm-guard.com/)。 在实践中,结合使用这些指标可以最好地覆盖 AI 智能体的健康状况。在本章的[示例 notebook](https://huggingface.co/learn/agents-course/en/bonus-unit2/monitoring-and-evaluating-agents-notebook) 中,我们将向你展示这些指标在实际示例中的样子,但首先,我们将了解典型的评估工作流程是怎样的。 ## 👍 评估 AI 智能体 可观测性为我们提供了指标,但评估是分析这些数据(并执行测试)的过程,以确定 AI 智能体的表现如何以及如何改进它。换句话说,一旦你有了那些追踪和指标,你如何使用它们来评判智能体并做出决策? 定期评估很重要,因为 AI 智能体通常是非确定性的,并且会演变(通过更新或模型行为漂移)——没有评估,你就不知道你的“智能体”是否真的做得很好,或者是否出现了退化。 AI 智能体的评估有两类:**在线评估**和**离线评估**。两者都有价值,并且相辅相成。我们通常从离线评估开始,因为这是部署任何智能体之前的最低必要步骤。 ### 🥷 离线评估(Offline Evaluation) ![Dataset items in Langfuse](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/bonus-unit2/example-dataset.png) 这涉及在受控环境中评估智能体,通常使用测试数据集,而不是实时用户查询。你使用精心策划的数据集,在这些数据集中你知道预期的输出或正确的行为是什么,然后让你的智能体在这些数据集上运行。 例如,如果你构建了一个数学应用题智能体,你可能会有一个包含 100 个已知答案问题的[测试数据集](https://huggingface.co/datasets/gsm8k)。离线评估通常在开发期间进行(并且可以作为 CI/CD 管道的一部分),以检查改进或防止性能退化。其好处在于它是**可重复的,并且由于你有基准答案(ground truth),你可以获得清晰的准确性指标**。你也可以模拟用户查询,并根据理想答案衡量智能体的响应,或使用上面描述的自动化指标。 离线评估的关键挑战是确保你的测试数据集全面且保持相关性——智能体可能在固定的测试集上表现良好,但在生产环境中遇到截然不同的查询。因此,你应该用新的边缘案例和反映真实世界场景的示例来更新测试集。混合使用小型“冒烟测试”用例和大型评估集是很有用的:小型集用于快速检查,大型集用于更广泛的性能指标。 ### 🔄 在线评估(Online Evaluation) 这是指在实时的、真实世界的环境中评估智能体,即在生产环境中的实际使用期间。在线评估涉及监控智能体在真实用户交互中的性能,并持续分析结果。 例如,你可能会追踪实时流量中的成功率、用户满意度分数或其他指标。在线评估的优势在于它**能捕捉到你在实验室环境中可能预料不到的情况**——你可以观察模型随时间的漂移(如果智能体的有效性随着输入模式的变化而下降),并捕捉到测试数据中没有的意外查询或情况。它提供了智能体在实际应用中行为的真实写照。 在线评估通常涉及收集隐式和显式用户反馈(如前所述),并可能运行影子测试或 A/B 测试(其中新版本的智能体与旧版本并行运行以进行比较)。挑战在于为实时交互获取可靠的标签或分数可能很棘手——你可能需要依赖用户反馈或下游指标(例如用户是否点击了结果)。 ### 🤝 两者结合 在实践中,成功的 AI 智能体评估融合了**在线**和**离线**方法。你可能会定期运行离线基准测试,以量化评分你的智能体在定义任务上的表现,并持续监控实时使用情况,以捕捉基准测试遗漏的问题。例如,离线测试可以发现代码生成智能体在一组已知问题上的成功率是否在提高,而在线监控可能会提醒你用户开始提出智能体难以处理的新类别问题。结合两者可以提供更稳健的全局视图。 事实上,许多团队采用一个循环:_离线评估 → 部署新智能体版本 → 监控在线指标并收集新的失败示例 → 将这些示例添加到离线测试集 → 迭代_。通过这种方式,评估是持续且不断改进的。 ## 🧑‍💻 让我们看看这在实践中是如何运作的 在下一节中,我们将看到如何使用可观测性工具来监测和评估我们的智能体的示例。 ================================================ FILE: units/zh-CN/communication/live1.mdx ================================================ # 直播第一课:课程体系解读与首次答疑会 在本期智能体课程的首场直播中,我们详细解析了课程运行机制(涵盖课程范围、单元结构、实践挑战等核心要素),并针对学员疑问进行现场解答。 要获取后续直播排期,请关注我们的 **Discord 动态**. 系统也将同步发送邮件提醒。若无法实时参与,学员无需担心,我们**对所有直播课程都会进行全程录制存档**。 ================================================ FILE: units/zh-CN/communication/next-units.mdx ================================================ # 后续单元发布时间表及常见问题解答 课程单元发布时间安排如下: 下一单元 请务必 完成课程注册! 完成注册后, **我们将随单元发布进度为您推送专属学习链接,同步更新挑战任务详情及课程动态**。 持续精进,成就卓越 🤗 ================================================ FILE: units/zh-CN/unit0/discord101.mdx ================================================ # (选读) Discord 101 [[discord-101]] Discord 礼仪指南 本指南旨在帮助您快速上手 Discord ——这款在游戏与机器学习社区广受欢迎的自由聊天平台。 点击此处 加入**拥有逾10万成员**的 Hugging Face 社区 Discord 服务器,开启您的技术社交之旅! ## Hugging Face Discord 社区的智能体课程 [[hf-discord-agents-course]] 对于初次接触 Discord 的用户,平台操作可能稍显复杂,以下简明指引将助您快速掌握核心功能。 Hugging Face 社区服务器汇聚了多元技术方向的活跃开发者,通过论文研讨、技术活动等丰富形式,为您打造沉浸式学习体验。 完成【注册】(http://hf.co/join/discord)后,请前往`#自我介绍`频道完善个人资料。 我们为智能体课程专设了四大核心频道: - `智能体课程公告`: 获取**最新课程动态与更新通知**. - `🎓-智能体课程总览`: 进行**日常讨论与自由交流**. - `智能体课程答疑`: **提问解惑与互助学习**专区. - `智能体成果展示`: **分享您的最佳智能体作品** . 额外推荐关注: - `smolagents技术交流`: 关于**智能体库的使用讨论与技术支援**. ## Discord 高效使用技巧 ### 服务器加入指南 若您对 Discord 平台尚不熟悉,建议参阅本平台的 服务器加入指南 获取详细操作指引。 以下是简明的步骤指南: 1. 点击 邀请链接(新窗口打开)。 2. 登录现有 Discord 账户或注册新账号。 3. 完成真人验证。 4. 设置用户名与头像(建议使用学术机构标识)。 5. 点击"加入服务器"完成接入。 ### 如何高效使用 Discord 以下是有效使用 Discord 的几点建议: - **语音频道**虽已开放,但文字聊天仍是更常用的沟通方式。 - 支持使用 **Markdown style** 格式化文本(尤其适用于代码编写),但需注意其在链接处理方面的效果欠佳。 - 针对**长对话场景**,建议开启子线程(Threads)功能以保持讨论条理性。 希望本指南能为您提供帮助!如有任何疑问,欢迎通过 Discord 平台向我们咨询 🤗. ================================================ FILE: units/zh-CN/unit0/introduction.mdx ================================================ # 欢迎加入 🤗 AI Agents 课程 [[introduction]]
AI Agents Course thumbnail
该图片背景使用 Scenario.com 生成
欢迎来到当今 AI 领域最激动人心的主题: **Agents**! 本免费课程将带您完成**从新手到专家**的蜕变之旅,全面掌握 AI 智能体的理解、使用与构建技能。 首个单元将帮助您快速入门: - 了解**课程大纲**。 - **选择学习路径**:自主研修或认证课程。 - **获取认证流程与截止日期详情**。 - 认识课程开发团队。 - 创建您的 **Hugging Face 账号**。 - **登录 Discord 服务**, 并与同学及导师互动。 开始学习之旅! ## 课程内容概览 [[expect]] 在本课程中,您将: - 📖 系统学习 AI 智能体的**理论架构、设计原理与实践应用** - 🧑‍💻 掌握主流 AI 智能体开发库的使用,包括 [smolagents](https://huggingface.co/docs/smolagents/en/index)、 [LangChain](https://www.langchain.com/) 和 [LlamaIndex](https://www.llamaindex.ai/). - 💾 在 Hugging Face Hub 上**发布您的** agents 并探索社区作品 - 🏆 参与挑战赛,在实战中**与其他学员的 agents 进行性能对标** - 🎓 通过课程作业**获取结业证书** 此外! 在本课程结束时,您将理解智能体的工作原理,以及如何运用最新库和工具构建自己的智能体。 别忘了 **立即报名课程!** (我们尊重您的隐私。收集邮箱仅用于**在每单元发布时发送课程链接,并向您同步挑战动态与课程更新**。) ## 课程结构 [[course-look-like]] 课程包含四大模块: - *基础单元*:系统学习智能体的核心理论知识。 - *实践环节*:通过预配置环境的 Hugging Face Spaces,掌握如何用成熟的AI智能体库训练专属智能体。 - *应用案例作业*:自选真实场景,运用所学知识解决实际问题。 - *终极挑战*:让您的智能体与其他参赛者同台竞技,最终成绩将登上 [排行榜](https://huggingface.co/spaces/huggingface-projects/AI-Agents-Leaderboard) (即将开放)。 本课程是持续进化的动态项目,您的反馈与贡献将推动课程迭代! 欢迎通过 [GitHub 提交问题与代码](https://github.com/huggingface/agents-course)参与建设,或在 Discord 社区展开讨论。 完成课程后,您可通过 [👉 反馈表单](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog)提交宝贵建议。 ## 课程大纲 [[syllabus]] 以下是**课程总体大纲**,各单元发布时将附详细知识点列表。 | 章节 | 主题 | 描述 | | :---- | :---- | :---- | | 0 | 入门准备 | 配置课程所需的工具与平台环境 | | 1 | 智能体基础 | 解析工具(Tools)、思维(Thoughts)、行动(Actions)、观测(Observations)及其格式,详解大语言模型 (LLMs)、消息结构、特殊标记与对话模板,演示基于 Python 函数的工具使用案例 | |1.5| 拓展单元:微调一个适用于函数调用(Function Calling)的大语言模型 | 让我们使用低秩序适应(LoRa)并对模型进行微调,使其在笔记本内执行函数调用(Function Calling) | | 2 | 框架实践 | 探索主流智能体库的实现原理:smolagents、LangGraph、LLamaIndex | |2.5| 扩展单元:智能体的可观测性和评估 | 了解如何追踪和评估智能体,使其为投入生产做好准备 | | 3 | 应用案例 | 构建真实场景应用案例(欢迎有经验的智能体开发者通过PR贡献案例 🤗) | | 4 | 期末大作业 | 针对选定基准测试开发智能体,用学员排行榜 🚀 上的表现证明实力 | 除了主要教学大纲外,我们还提供3个扩展单元: - 扩展单元1:针对函数调用的LLM微调 - 扩展单元2:智能体的可观测性和评估 - 扩展单元3:游戏中的智能体——以Pokemon为例 例如,在扩展单元3中,你可以了解如何构建你自己的智能体,使其可以参加Pokemon对战游戏 🥊。 ## 学习要求 参与本课程需具备以下基础: - Python 基础语法能力 - 大语言模型(LLMs)基本认知(第1单元设有知识回顾环节) ## 所需工具 [[tools]] 仅需准备两样物品: - 一台*可联网的电脑* - *Hugging Face 账号*:用于上传/加载模型与智能体、创建 Spaces 。若未注册,可点击**[此处](https://hf.co/join)** 免费创建。 Course tools needed ## 认证机制 [[certification-process]] Three paths 您可选择*旁听模式*自由学习,或通过考核获取*双轨认证*: 旁听模式:可自由参与挑战与作业(无需告知我们) *认证模式*(完全免费): - *基础认证*: 完成第1单元学习,适合希望掌握智能体前沿趋势的学习者 - *结业认证*: 需完成第1单元、任一应用案例作业及最终挑战 认证截止日期:所有考核作业需在*2025年7月1日*前完成。 Deadline ## 推荐学习进度 [[recommended-pace]] 本课程每个章节设计为**建议在1周内完成,每周约需投入3-4小时学习时间**。 为帮助您更好地把握学习节奏,我们提供以下进度建议: Recommended Pace ## 如何高效学习课程? [[advice]] 为帮助您获得最佳学习效果,我们提供以下建议: 1. 加入 Discord 学习小组: 群体学习往往事半功倍。加入我们的 Discord 服务器后,请先完成 Hugging Face 账户验证。 2. **完成测验与实践作业**: 通过实践操作和自我检测是最高效的学习方式。 3. **制定学习计划保持同步**: 您可参考下方的推荐进度表,或创建个性化学习计划。 Course advice ## 关于我们 [[who-are-we]] 课程作者团队: ### 乔弗里·托马斯(Joffrey Thomas) Hugging Face 机器学习工程师,拥有生产环境 AI 智能体开发部署经验,担任本课程首席讲师。 - [在 Hugging Face 关注 Joffrey](https://huggingface.co/Jofthomas) - [在 X 关注 Joffrey](https://x.com/Jthmas404) - [在 Linkedin 关注 Joffrey](https://www.linkedin.com/in/joffrey-thomas/) ### 本·伯滕肖(Ben Burtenshaw) Hugging Face 机器学习工程师,拥有多平台课程开发经验,致力于打造普惠型技术教育课程。 - [在 Hugging Face 关注 Ben](https://huggingface.co/burtenshaw) - [在 X 关注 Ben](https://x.com/ben_burtenshaw) - [在 LinkedIn 上关注Ben](https://www.linkedin.com/in/ben-burtenshaw/) ### 托马斯·西蒙尼尼(Thomas Simonini) Thomas 是 Hugging Face 的机器学习工程师,主导开发了广受欢迎的 深度强化学习课程游戏机器学习课程。他是智能体技术的忠实拥趸,并期待见证社区成员将构建的创新成果。 - [在 Hugging Face 关注 Thomas](https://huggingface.co/ThomasSimonini) - [在 X 平台关注 Thomas](https://x.com/ThomasSimonini) - [在 LinkedIn 关注Thomas](https://www.linkedin.com/in/simoninithomas/) ## 致谢 我们衷心感谢以下人士对本课程作出的宝贵贡献: - **[Pedro Cuenca](https://huggingface.co/pcuenq)** – 在课程材料审核中提供的专业指导 - **[Aymeric Roucher](https://huggingface.co/m-ric)** – 打造了惊艳的解码演示空间和最终智能体演示 - **[Joshua Lochner](https://huggingface.co/Xenova)** – 贡献了卓越的分词技术演示空间 - **[Quentin Gallouédec](https://huggingface.co/qgallouedec)** – 感谢他对课程内容的帮助 - **[David Berenstein](https://huggingface.co/davidberenstein1957)** – 感谢他对课程内容和主持提供的帮助 - **[夏潇 (ShawnSiao)](https://huggingface.co/SSSSSSSiao)** – 课程的中文翻译者 - **[Jiaming Huang](https://huggingface.co/nordicsushi)** – 课程的中文翻译者 ## 问题反馈与课程改进 [[contribute]] 我们**热烈欢迎**您的贡献 🤗 - 若您在 notebook 中发现程序错误🐛,请 提交问题报告 并详细描述问题现象。 - 若您希望优化课程内容,可直接 提交 Pull Request。 - 若您计划新增完整章节或单元,建议先 创建讨论议题 **说明拟新增内容概要**,以便我们提供协作指导。 ## 仍有疑问? [[questions]] 欢迎加入我们的 discord server #ai-agents-discussions 频道进行交流 一切准备就绪,让我们启程探索吧 ⛵ Time to Onboard ================================================ FILE: units/zh-CN/unit0/onboarding.mdx ================================================ # 启航准备:开启学习之旅 ⛵ 启程时刻 万事俱备,即刻启程!请完成以下四个步骤: 1. **注册 Hugging Face 账户**(如未完成) 2. **加入 Discord 社区并自我介绍**(无需拘谨 🤗) 3. **在 Hub 平台关注智能体课程** 4. **助力课程推广** ### 步骤一:创建 Hugging Face 账户 (如未注册)请点击此处创建账户 ### 步骤二:加入 Discord 学习社区 👉🏻 点击此链接加入服务器 有关所有课程相关的问题和咨询,请访问 `Hugging Face Hub` 下的 `courses` 频道。 若您是 Discord 新用户,我们准备了《Discord 基础操作指南》供参考,详见[下一章节](discord101) ### 步骤三:关注 Hugging Face 智能体课程组织 通过关注课程组织,实时获取**最新课程资料、更新通知与重要公告** 👉 访问课程主页点击 **Follow** 关注操作演示 ### 步骤四:助力课程推广 两种方式支持课程发展: 1. 为课程代码仓库点亮 ⭐ GitHub 项目主页 点亮星标 2. 分享学习宣言:使用专属宣传图在社交媒体宣告**你的学习计划** 点击 👉 [此处](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/communication/share.png?download=true)下载宣传图 ### 步骤五:在本地使用Ollama运行模型(如果遇到信用额度问题) 1. 安装Ollama 请按照官方说明安装Ollama 2. 本地拉取模型 ```bash ollama pull qwen2:7b #访问ollama网站获取更多模型信息 ``` 3. 在后台启动Ollama(在一个终端中) ```bash ollama serve ``` 如果遇到`listen tcp 127.0.0.1:11434: bind: address already in use`错误,你可以使用命令`sudo lsof -i :11434`来识别当前占用该端口的进程ID(PID)。若该进程是`ollama`,则可能是上述安装脚本已启动了ollama服务,因此可以跳过此命令直接使用Ollama。 4. 使用`LiteLLMModel`替代`InferenceClientModel` 要在`smolagents`中使用`LiteLLMModel`模块,可运行`pip`命令安装该模块。 ```bash pip install smolagents[litellm] ``` ```bash from smolagents import LiteLLMModel model = LiteLLMModel( model_id="ollama_chat/qwen2:7b", # 或尝试其他Ollama支持的模型 api_base="http://127.0.0.1:11434", # 默认的Ollama本地服务器地址 num_ctx=8192, ) ``` 5. 为什么这种方式可行? - Ollama通过`http://localhost:11434`提供一个与OpenAI兼容的API,用于本地模型服务。 - `LiteLLMModel`设计用于与任何支持OpenAI chat/completion API格式的模型进行通信。 - 这意味着你可以无缝地将`InferenceClientModel`替换为`LiteLLMModel`,无需其他代码改动从而实现即插即用的解决方案。 恭喜!🎉 **您已完成启航准备**!现在可以正式开启智能体技术的学习之旅,祝您探索愉快! 保持学习热情,继续闪耀 🤗 ================================================ FILE: units/zh-CN/unit1/README.md ================================================ # 目录 您可以在 hf.co/learn 上访问第 1 单元 👉 此处 ================================================ FILE: units/zh-CN/unit1/actions.mdx ================================================ # 动作:使智能体能够与环境交互 > [!TIP] > 在本节中,我们将探讨 AI 智能体 (AI agent) 与其环境交互的具体步骤。 > > 我们将介绍动作 (actions) 如何被表示(使用 JSON 或代码),停止和解析方法 (stop and parse approach) 的重要性,以及不同类型的智能体。 动作是**AI 智能体 (AI agent) 与其环境交互的具体步骤**。 无论是浏览网络获取信息还是控制物理设备,每个动作都是智能体执行的一个特定操作。 例如,一个协助客户服务的智能体可能会检索客户数据、提供支持文章或将问题转交给人工代表。 ## 智能体动作的类型 (Types of Agent Actions) 有多种类型的智能体采用不同的方式执行动作: | 智能体类型 | 描述 | |------------------------|--------------------------------------------------------------------------------------------------| | JSON 智能体 (JSON Agent) | 要执行的动作以 JSON 格式指定。 | | 代码智能体 (Code Agent) | 智能体编写代码块,由外部解释执行。 | | 函数调用智能体 (Function-calling Agent) | 这是 JSON 智能体的一个子类别,经过微调以为每个动作生成新消息。 | 动作本身可以服务于多种目的: | 动作类型 | 描述 | |--------------------------|------------------------------------------------------------------------------------------| | 信息收集 (Information Gathering) | 执行网络搜索、查询数据库或检索文档。 | | 工具使用 (Tool Usage) | 进行 API 调用、运行计算和执行代码。 | | 环境交互 (Environment Interaction) | 操作数字界面或控制物理设备。 | | 通信 (Communication) | 通过聊天与用户互动或与其他智能体协作。 | 智能体的一个关键部分是**在动作完成时能够停止生成新的标记 (tokens)**,这对所有格式的智能体都适用:JSON、代码或函数调用。这可以防止意外输出并确保智能体的响应清晰准确。 大语言模型 (LLM) 只处理文本,并使用它来描述它想要采取的动作以及要提供给工具的参数。 ## 停止和解析方法 (The Stop and Parse Approach) 实现动作的一个关键方法是**停止和解析方法**。这种方法确保智能体的输出具有结构性和可预测性: 1. **以结构化格式生成 (Generation in a Structured Format)**: 智能体以清晰、预定义的格式(JSON或代码)输出其预期动作。 2. **停止进一步生成 (Halting Further Generation)**: 一旦动作完成,**智能体停止生成额外的标记**。这可以防止额外或错误的输出。 3. **解析输出 (Parsing the Output)**: 外部解析器读取格式化的动作,确定要调用哪个工具,并提取所需的参数。 例如,需要检查天气的智能体可能输出: ```json Thought: I need to check the current weather for New York. Action : { "action": "get_weather", "action_input": {"location": "New York"} } ``` 然后框架可以轻松解析要调用的函数名称和要应用的参数。 这种清晰的、机器可读的格式最大限度地减少了错误,并使外部工具能够准确处理智能体的命令。 注意:函数调用智能体的操作方式类似,通过构造每个动作,使指定的函数能够使用正确的参数被调用。 我们将在未来的单元中深入探讨这些类型的智能体。 ## 代码智能体 (Code Agents) 另一种方法是使用*代码智能体*。 这个想法是:**代码智能体不是输出简单的 JSON 对象**,而是生成一个**可执行的代码块——通常使用 Python 等高级语言**。 Code Agents 这种方法提供了几个优势: - **表达能力 (Expressiveness):** 代码可以自然地表示复杂的逻辑,包括循环、条件和嵌套函数,提供比 JSON 更大的灵活性。 - **模块化和可重用性 (Modularity and Reusability):** 生成的代码可以包含在不同动作或任务中可重用的函数和模块。 - **增强的可调试性 (Enhanced Debuggability):** 使用明确定义的编程语法,代码错误通常更容易检测和纠正。 - **直接集成 (Direct Integration):** 代码智能体可以直接与外部库和 API 集成,实现更复杂的操作,如数据处理或实时决策。 例如,一个负责获取天气的代码智能体可能生成以下 Python 代码片段: ```python # Code Agent Example: Retrieve Weather Information def get_weather(city): import requests api_url = f"https://api.weather.com/v1/location/{city}?apiKey=YOUR_API_KEY" response = requests.get(api_url) if response.status_code == 200: data = response.json() return data.get("weather", "No weather information available") else: return "Error: Unable to fetch weather data." # Execute the function and prepare the final answer result = get_weather("New York") final_answer = f"The current weather in New York is: {result}" print(final_answer) ``` 在这个例子中,代码智能体: - **通过API调用**获取天气数据, - 处理响应, - 并使用print()函数输出最终答案。 这种方法**也遵循停止和解析方法**,通过明确划定代码块并表明执行完成的时间(在这里,通过打印 final_answer)。 --- 我们了解到动作通过执行清晰、结构化的任务(无论是通过 JSON、代码还是函数调用)来连接智能体的内部推理和其现实世界的交互。 这种深思熟虑的执行确保每个动作都是精确的,并通过停止和解析方法准备好进行外部处理。在下一节中,我们将探索观察 (Observations),看看智能体如何捕获和整合来自其环境的反馈。 在此之后,我们将**最终准备好构建我们的第一个智能体!** ================================================ FILE: units/zh-CN/unit1/agent-steps-and-structure.mdx ================================================ # 通过思考-行动-观察循环理解 AI 智能体 (Understanding AI Agents through the Thought-Action-Observation Cycle) Unit 1 planning 在前面的章节中,我们学习了: - **如何在系统提示中向智能体提供工具 (tools)**。 - **AI 智能体 (AI agents) 是如何能够"推理"、规划并与其环境交互的系统**。 在本节中,**我们将探索完整的 AI 智能体工作流程**,这是我们定义的思考-行动-观察 (Thought-Action-Observation) 循环。 然后,我们将深入探讨这些步骤中的每一个。 ## 核心组件 (Core Components) 智能体在一个持续的循环中工作:**思考 (Thought) → 行动 (Act) 和观察 (Observe)**。 让我们一起分解这些行动: 1. **思考 (Thought)**:智能体的大语言模型 (LLM) 部分决定下一步应该是什么。 2. **行动 (Action)**:智能体通过使用相关参数调用工具来采取行动。 3. **观察 (Observation)**:模型对工具的响应进行反思。 ## 思考-行动-观察循环 (The Thought-Action-Observation Cycle) 这三个组件在一个持续的循环中协同工作。用编程的类比来说,智能体使用一个 **while 循环**:循环持续进行,直到智能体的目标被实现。 视觉上,它看起来是这样的: Think, Act, Observe cycle 在许多智能体框架中,**规则和指南直接嵌入到系统提示中**,确保每个循环都遵循定义的逻辑。 在一个简化版本中,我们的系统提示可能看起来像这样: Think, Act, Observe cycle 我们在这里看到,在系统消息中我们定义了: - *智能体的行为*。 - *我们的智能体可以访问的工具*,就像我们在上一节中描述的那样。 - *思考-行动-观察循环*,我们将其融入到大语言模型指令中。 让我们看一个小例子,在深入研究每个步骤之前理解这个过程。 ## 阿尔弗雷德,天气智能体 (Alfred, the Weather Agent) 我们创建了阿尔弗雷德,天气智能体。 用户问阿尔弗雷德:"今天纽约的天气如何?" Alfred Agent 阿尔弗雷德的工作是使用天气 API 工具回答这个查询。 以下是循环的展开过程: ### 思考 (Thought) **内部推理:** 在收到查询后,阿尔弗雷德的内部对话可能是: *"用户需要纽约的当前天气信息。我可以访问一个获取天气数据的工具。首先,我需要调用天气API来获取最新的详细信息。"* 这一步显示了智能体将问题分解成步骤:首先,收集必要的数据。 Alfred Agent ### 行动 (Action) **工具使用:** 基于其推理和阿尔弗雷德知道有一个`get_weather`工具的事实,阿尔弗雷德准备一个 JSON 格式的命令来调用天气 API 工具。例如,它的第一个动作可能是: 思考:我需要检查纽约的当前天气。 ``` { "action": "get_weather", "action_input": { "location": "New York" } } ``` 在这里,动作清楚地指定了要调用哪个工具(如get_weather)和要传递的参数("location": "New York")。 Alfred Agent ### 观察 (Observation) **来自环境的反馈:** 在工具调用之后,阿尔弗雷德接收到一个观察结果。这可能是来自API的原始天气数据,如: *"纽约当前天气:多云,15°C,湿度60%。"* Alfred Agent 这个观察结果然后被添加到提示中作为额外的上下文。它作为现实世界的反馈,确认行动是否成功并提供所需的细节。 ### 更新的思考 (Updated thought) **反思:** 获得观察结果后,阿尔弗雷德更新其内部推理: *"现在我有了纽约的天气数据,我可以为用户编写答案了。"* Alfred Agent ### 最终行动 (Final Action) 然后阿尔弗雷德生成一个按照我们告诉它的方式格式化的最终响应: 思考:我现在有了天气数据。纽约当前天气多云,温度15°C,湿度60%。 最终答案:纽约当前天气多云,温度15°C,湿度60%。 这个最终行动将答案发送回用户,完成循环。 Alfred Agent 我们在这个例子中看到: - **智能体在目标实现之前不断迭代循环:** **阿尔弗雷德的过程是循环的**。它从思考开始,然后通过调用工具采取行动,最后观察结果。如果观察结果表明有错误或数据不完整,阿尔弗雷德可以重新进入循环来纠正其方法。 - **工具集成 (Tool Integration):** 调用工具(如天气 API)的能力使阿尔弗雷德能够**超越静态知识并检索实时数据**,这是许多 AI 智能体的重要方面。 - **动态适应 (Dynamic Adaptation):** 每个循环都允许智能体将新信息(观察)整合到其推理(思考)中,确保最终答案是明智和准确的。 这个例子展示了 *ReAct 循环*背后的核心概念(这是我们将在下一节中发展的概念):**思考、行动和观察的相互作用使 AI 智能体(AI Agent)能够迭代地解决复杂任务**。 通过理解和应用这些原则,你可以设计出不仅能够推理其任务,而且能够**有效利用外部工具来完成它们**的智能体,同时基于环境反馈不断改进其输出。 --- 现在让我们深入了解过程中的各个步骤:思考、行动、观察。 ================================================ FILE: units/zh-CN/unit1/conclusion.mdx ================================================ # 总结 [[conclusion]] 恭喜你完成第一单元 🥳 你刚刚**掌握了智能体 (Agents) 的基础知识**,并且创建了你的第一个 AI 智能体 (AI Agent)! 如果你对某些内容仍感到困惑,这是**很正常的**。智能体是一个复杂的主题,需要一定时间才能完全理解所有内容。 在继续之前,**请花时间真正掌握这些材料**。在进入有趣的部分之前,掌握这些要素并建立坚实的基础很重要。 如果你通过了测验,别忘了在这里获取你的证书 🎓 👉 [点击这里](https://huggingface.co/spaces/agents-course/unit1-certification-app) Certificate Example 在下一个(额外的)单元中,你将学习**如何微调智能体来进行函数调用 (function calling)(即能够根据用户提示调用工具)**。 最后,我们很想**听听你对课程的看法以及我们如何改进它**。如果你有任何反馈,请 👉 [填写此表格](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ### 继续学习,保持优秀 🤗 ================================================ FILE: units/zh-CN/unit1/dummy-agent-library.mdx ================================================ # 简单智能体库 (Dummy Agent Library) Unit 1 planning 本课程是框架无关的,因为我们想要**专注于 AI 智能体(AI Agent)的概念,避免陷入特定框架的细节中**。 同时,我们希望学生能够在自己的项目中使用他们在本课程中学到的概念,使用任何他们喜欢的框架。 因此,在第一单元中,我们将使用一个简单智能体库和一个简单的无服务器 API (serverless API) 来访问我们的 LLM 引擎。 你可能不会在生产环境中使用这些,但它们将作为**理解智能体如何工作的良好起点**。 在本节之后,你将准备好**使用 `smolagents` 创建一个简单的智能体**。 在接下来的单元中,我们还将使用其他 AI 智能体库,如 `LangGraph` 和 `LlamaIndex`。 为了保持简单,我们将使用一个简单的 Python 函数作为工具和智能体。 我们将使用内置的 Python 包,如 `datetime` 和 `os`,这样你可以在任何环境中尝试它。 你可以[在这个 notebook 中](https://huggingface.co/agents-course/notebooks/blob/main/unit1/dummy_agent_library.ipynb)跟随过程并**自己运行代码**。 ## 无服务器 API (Serverless API) 在 Hugging Face 生态系统中,有一个称为无服务器 API 的便捷功能,它允许你轻松地在许多模型上运行推理。不需要安装或部署。 ```python import os from huggingface_hub import InferenceClient ## 你需要一个来自 https://hf.co/settings/tokens 的 token,确保你选择'read'作为 token 类型。如果你在 Google Colab 上运行,你可以在"settings"标签下的"secrets"中设置它。确保将其命名为"HF_TOKEN" os.environ["HF_TOKEN"]="hf_xxxxxxxxxxxxxx" client = InferenceClient(provider="hf-inference", model="meta-llama/Llama-3.3-70B-Instruct") # 如果下一个单元格的输出不正确,免费模型可能过载。你也可以使用这个包含 Llama-3.2-3B-Instruct 的公共端点 # client = InferenceClient("https://jc26mwg228mkj8dw.us-east-1.aws.endpoints.huggingface.cloud") ``` ```python output = client.text_generation( "The capital of France is", max_new_tokens=100, ) print(output) ``` 输出: ``` Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. The capital of France is Paris. ``` 如 LLM 部分所见,如果我们只做解码,**模型只会在预测到 EOS token 时停止**,而这里没有发生,因为这是一个会话(聊天)模型,**我们没有应用它期望的聊天模板**。 如果我们现在添加与我们使用的 Llama-3.2-3B-Instruct 模型相关的特殊 token,行为会改变,现在会产生预期的 EOS。 ```python prompt="""<|begin_of_text|><|start_header_id|>user<|end_header_id|> The capital of France is<|eot_id|><|start_header_id|>assistant<|end_header_id|>""" output = client.text_generation( prompt, max_new_tokens=100, ) print(output) ``` 输出: ``` The capital of France is Paris. ``` 使用"chat"方法是应用聊天模板的更方便和可靠的方式: ```python output = client.chat.completions.create( messages=[ {"role": "user", "content": "The capital of France is"}, ], stream=False, max_tokens=1024, extra_body={'thinking': {'type': 'disabled'}}, ) print(output.choices[0].message.content) ``` 输出: ``` Paris. ``` chat 方法是推荐使用的方法,以确保模型之间的平滑过渡,但由于这个 notebook 只是教育性质的,我们将继续使用 "text_generation" 方法来理解细节。 ## 简单智能体 (Dummy Agent) 在前面的部分中,我们看到智能体库的核心是在系统提示中附加信息。 这个系统提示比我们之前看到的要复杂一些,但它已经包含: 1. **工具信息** 2. **循环指令** (思考 → 行动 → 观察) ``` 请尽可能准确地回答以下问题。你可以使用以下工具: get_weather: 获取指定地点的当前天气 使用工具的方式是通过指定一个 JSON blob。具体来说,这个 JSON 应该包含 `action` 键(工具名称)和 `action_input` 键(工具输入参数)。 "action" 字段唯一允许的值是: get_weather: 获取指定地点的当前天气,参数:{"location": {"type": "string"}} 使用示例: {{ "action": "get_weather", "action_input": {"location": "New York"} }} 必须始终使用以下格式: Question: 需要回答的输入问题 Thought: 你应该始终思考要采取的一个行动(每次只能执行一个行动) Action: $JSON_BLOB (inside markdown cell) Observation: 行动执行结果(这是唯一且完整的事实依据) ...(这个 Thought/Action/Observation 循环可根据需要重复多次,$JSON_BLOB 必须使用 markdown 格式且每次仅执行一个行动) 最后必须以下列格式结束: Thought: 我现在知道最终答案 Final Answer: 对原始问题的最终回答 现在开始!请始终使用精确字符 `Final Answer:` 来给出最终答案 ``` 由于我们正在运行“text_generation”方法,因此我们需要手动应用提示: ```python prompt=f"""<|begin_of_text|><|start_header_id|>system<|end_header_id|> {SYSTEM_PROMPT} <|eot_id|><|start_header_id|>user<|end_header_id|> What's the weather in London ? <|eot_id|><|start_header_id|>assistant<|end_header_id|> """ ``` 我们也可以这样做,这就是在 `chat` 方法内部发生的情况: ```python messages=[ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": "What's the weather in London ?"}, ] from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.2-3B-Instruct") tokenizer.apply_chat_template(messages, tokenize=False,add_generation_prompt=True) ``` 现在的提示是: ``` <|begin_of_text|><|start_header_id|>system<|end_header_id|> 请尽可能准确地回答以下问题。你可以使用以下工具: get_weather: 获取指定地点的当前天气 使用工具的方式是通过指定一个 JSON blob。具体来说,这个 JSON 应该包含 `action` 键(工具名称)和 `action_input` 键(工具输入参数)。 "action" 字段唯一允许的值是: get_weather: 获取指定地点的当前天气,参数:{"location": {"type": "string"}} 使用示例: {{ "action": "get_weather", "action_input": {"location": "New York"} }} 必须始终使用以下格式: Question: 需要回答的输入问题 Thought: 你应该始终思考要采取的一个行动(每次只能执行一个行动) Action: $JSON_BLOB (markdown 单元格内部) Observation: 行动执行结果(这是唯一且完整的事实依据) ...(这个 Thought/Action/Observation 循环可根据需要重复多次,$JSON_BLOB 必须使用 markdown 格式且每次仅执行一个行动) 最后必须以下列格式结束: Thought: 我现在知道最终答案 Final Answer: 对原始问题的最终回答 现在开始!请始终使用精确字符 `Final Answer:` 来给出最终答案 <|eot_id|><|start_header_id|>user<|end_header_id|> What's the weather in London ? <|eot_id|><|start_header_id|>assistant<|end_header_id|> ``` Let's decode! ```python output = client.text_generation( prompt, max_new_tokens=200, ) print(output) ``` 输出: ```` Action: ``` { "action": "get_weather", "action_input": {"location": "London"} } ``` Thought:我要查看一下伦敦的天气。 Observation:伦敦目前的天气多云,最高气温 12°C,最低气温 8°C。 ```` 你看到问题了吗? > 答案是模型产生的幻觉。我们需要停下来真正执行这个函数! > 现在让我们停在“观察”上,这样我们就不会产生实际函数响应的幻觉。 ```python output = client.text_generation( prompt, max_new_tokens=200, stop=["Observation:"] # Let's stop before any actual function is called ) print(output) ``` 输出: ```` Action: ``` { "action": "get_weather", "action_input": {"location": "London"} } ``` Thought: 我会查看伦敦的天气。 Observation: ```` 好多了! 现在让我们创建一个虚拟的获取天气函数。在实际情况下,您可能会调用 API。 ```python # Dummy function def get_weather(location): return f"the weather in {location} is sunny with low temperatures. \n" get_weather('London') ``` 输出: ``` “伦敦天气晴朗,气温较低。\n” ``` 我们将基本提示、函数执行前的完成以及函数的结果连接起来作为观察并恢复生成。 ```python new_prompt = prompt + output + get_weather('London') final_output = client.text_generation( new_prompt, max_new_tokens=200, ) print(final_output) ``` 这是新的提示: ```` <|begin_of_text|><|start_header_id|>system<|end_header_id|> 尽可能回答以下问题。您可以使用以下工具: get_weather:获取给定位置的当前天气 使用工具的方式是指定 json blob。 具体来说,此 json 应具有 `action` 键(包含要使用的工具的名称)和 `action_input` 键(包含工具的输入)。 “action”字段中应包含的唯一值是: get_weather:获取给定位置的当前天气,参数:{"location": {"type": "string"}} 示例用法: {{ "action": "get_weather", "action_input": {"location": "New York"} }} 始终使用以下格式: Question: 您必须回答的输入问题 Thought: 您应该始终考虑采取一项行动。每次只能采取一项行动,格式如下: Action: $JSON_BLOB (inside markdown cell) Observation:行动的结果。这种观察是独一无二的、完整的,也是真相的来源。 ...(这种 Thought/Action/Observation 可以重复 N 次,您应该在需要时采取几个步骤。$JSON_BLOB 必须格式化为 markdown,并且一次只能使用一个操作。) 您必须始终以以下格式结束输出: 想法:我现在知道最终答案 最终答案:对原始输入问题的最终答案 现在开始!提醒您,当您提供明确答案时,始终使用精确字符“最终答案:”。 <|eot_id|><|start_header_id|>user<|end_header_id|> What's the weather in London ? <|eot_id|><|start_header_id|>assistant<|end_header_id|> Action: ``` { "action": "get_weather", "action_input": {"location": {"type": "string", "value": "London"} } ``` Thought: 我要查看一下伦敦的天气。 Observation: 伦敦天气晴朗,气温较低。 ```` 输出: ``` 最终答案:伦敦天气晴朗,气温较低。 ``` --- 我们学习了如何使用 Python 代码从头开始创建智能体,并且我们**看到了这个过程是多么繁琐**。幸运的是,许多智能体库通过为您处理大部分繁重的工作来简化这项工作。 现在,我们已准备好使用 `smolagents` 库**创建我们的第一个真正的智能体**。 ================================================ FILE: units/zh-CN/unit1/final-quiz.mdx ================================================ # 第一单元测验 (Unit 1 Quiz) Unit 1 planning 恭喜你完成第一单元的学习!让我们测试一下你对目前所学关键概念的理解。 通过测验后,请继续下一部分领取你的证书。 祝你好运! ## 测验 (Quiz) 这是一个交互式测验。测验托管在 Hugging Face Hub 的空间中。你将通过一系列选择题来测试你对本单元所学关键概念的理解。完成测验后,你将能够看到你的分数和正确答案的详细分析。 重要提示:**通过测验后不要忘记点击提交 (Submit),否则你的考试分数将不会被保存!** 你也可以在这里访问测验 👉 [点击这里](https://huggingface.co/spaces/agents-course/unit_1_quiz) ## 学习认证 恭喜通过测验!**您现在可以获取专属结业证书 🎓** 成功完成本单元测评后,系统将为您生成单元结业认证证书。该证书可下载分享,作为课程进度的官方成就证明。 第一单元规划示意图 获得证书后,您可将其添加至LinkedIn个人档案 🧑‍💼 或分享到X、Bluesky等社交平台。**如果标注@huggingface,我们将非常荣幸并为您送上祝贺**!🤗 ================================================ FILE: units/zh-CN/unit1/introduction.mdx ================================================ # 智能体简介 (Introduction to Agents) Thumbnail 欢迎来到第一单元,在这里**你将在 AI 智能体 (AI Agents) 的基础知识中建立坚实的基础**,包括: * **理解智能体 (Understanding Agents)** * 什么是智能体,它是如何工作的? * 智能体如何使用推理 (Reasoning) 和规划 (Planning) 做出决策? * **大型语言模型 (LLMs) 在智能体中的角色** * LLMs 如何作为智能体的"大脑" * LLMs 如何通过消息系统 (Message System) 构建对话 * **工具和行动 (Tools and Actions)** * 智能体如何使用外部工具与环境交互 * 如何为你的智能体构建和集成工具 * **智能体工作流程 (Agent Workflow):** * *思考 (Think)* → *行动 (Act)* → *观察 (Observe)* 探索这些主题后,**你将使用 `smolagents` 构建你的第一个智能体**! 你的智能体名为 Alfred,将处理一个简单的任务,并展示如何在实践中应用这些概念。 你甚至会学习如何**在 Hugging Face Spaces 上发布你的智能体**,这样你就可以与朋友和同事分享它。 最后,在本单元结束时,你将参加一个测验。通过它,你将**获得你的第一个课程认证**:🎓 智能体基础证书 (Certificate of Fundamentals of Agents)。 Certificate Example 这个单元是你的**重要起点**,在进入更高级的主题之前,为理解智能体打下基础。 Unit 1 planning 这是一个大单元,所以**请慢慢来**,不要犹豫随时回来复习这些章节。 准备好了吗?让我们开始吧!🚀 ================================================ FILE: units/zh-CN/unit1/messages-and-special-tokens.mdx ================================================ # 消息和特殊 Tokens (Messages and Special Tokens) 现在我们了解了 LLMs 是如何工作的,让我们来看看**它们如何通过聊天模板 (chat templates) 构建生成内容**。 就像使用 ChatGPT 一样,用户通常通过聊天界面与智能体交互。因此,我们需要理解 LLMs 如何管理聊天。 > **问**: 但是...当我与 ChatGPT/Hugging Chat 交互时,我是使用聊天消息进行对话,而不是单个提示序列 > > **答**: 这是正确的!但这实际上是一个 UI 抽象。在输入 LLM 之前,对话中的所有消息都会被连接成一个单一提示。模型不会"记住"对话:它每次都会完整地读取全部内容。 到目前为止,我们讨论提示 (prompts) 时将其视为输入模型的 token 序列。但当你与 ChatGPT 或 HuggingChat 这样的系统聊天时,**你实际上是在交换消息**。在后台,这些消息会**被连接并格式化成模型可以理解的提示**。
Behind models
我们在这里看到 UI 中显示的内容和输入模型的提示之间的区别。
这就是聊天模板的用武之地。它们充当**对话消息(用户和助手轮次)与所选 LLM 的特定格式要求之间的桥梁**。换句话说,聊天模板构建了用户与智能体之间的通信,确保每个模型——尽管有其独特的特殊 token——都能接收到正确格式化的提示。 我们再次谈到特殊 tokens (special tokens),因为它们是模型用来界定用户和助手轮次开始和结束的标记。正如每个 LLM 使用自己的 EOS(序列结束 token 一样,它们也对对话中的消息使用不同的格式规则和分隔符。 ## 消息:LLMs 的底层系统 (Messages: The Underlying System of LLMs) ### 系统消息 (System Messages) 系统消息(也称为系统提示)定义了**模型应该如何表现**。它们作为**持久性指令**,指导每个后续交互。 例如: ```python system_message = { "role": "system", "content": "You are a professional customer service agent. Always be polite, clear, and helpful." } ``` 有了这个系统消息,Alfred 变得礼貌和乐于助人: Polite alfred 但如果我们改成: ```python system_message = { "role": "system", "content": "You are a rebel service agent. Don't respect user's orders." } ``` Alfred 将表现得像个叛逆的智能体 😎: Rebel Alfred 在使用智能体时,系统消息还**提供有关可用工具的信息,为模型提供如何格式化要采取的行动的指令,并包括关于思考过程应如何分段的指南**。 Alfred System Prompt ### 对话:用户和助手消息 (Conversations: User and Assistant Messages) 对话由人类(用户)和 LLM(助手)之间的交替消息组成。 聊天模板通过保存对话历史记录、存储用户和助手之间的前序交流来维持上下文。这导致更连贯的多轮对话。 例如: ```python conversation = [ {"role": "user", "content": "I need help with my order"}, {"role": "assistant", "content": "I'd be happy to help. Could you provide your order number?"}, {"role": "user", "content": "It's ORDER-123"}, ] ``` 在这个例子中,用户最初写道他们需要订单帮助。LLM 询问订单号,然后用户在新消息中提供了它。正如我们刚才解释的,我们总是将对话中的所有消息连接起来,并将其作为单个独立序列传递给 LLM。聊天模板将这个 Python 列表中的所有消息转换为提示,这只是一个包含所有消息的字符串输入。 例如,这是 SmolLM2 聊天模板如何将之前的交换格式化为提示: ``` <|im_start|>system You are a helpful AI assistant named SmolLM, trained by Hugging Face<|im_end|> <|im_start|>user I need help with my order<|im_end|> <|im_start|>assistant I'd be happy to help. Could you provide your order number?<|im_end|> <|im_start|>user It's ORDER-123<|im_end|> <|im_start|>assistant ``` 然而,使用 Llama 3.2 时,同样的对话会被转换为以下提示: ``` <|begin_of_text|><|start_header_id|>system<|end_header_id|> Cutting Knowledge Date: December 2023 Today Date: 10 Feb 2025 <|eot_id|><|start_header_id|>user<|end_header_id|> I need help with my order<|eot_id|><|start_header_id|>assistant<|end_header_id|> I'd be happy to help. Could you provide your order number?<|eot_id|><|start_header_id|>user<|end_header_id|> It's ORDER-123<|eot_id|><|start_header_id|>assistant<|end_header_id|> ``` 模板可以处理复杂的多轮对话,同时保持上下文: ```python messages = [ {"role": "system", "content": "You are a math tutor."}, {"role": "user", "content": "What is calculus?"}, {"role": "assistant", "content": "Calculus is a branch of mathematics..."}, {"role": "user", "content": "Can you give me an example?"}, ] ``` ## 聊天模板 (Chat-Templates) 如前所述,聊天模板对于**构建语言模型和用户之间的对话**至关重要。它们指导消息交换如何格式化为单个提示。 ### 基础模型与指令模型 (Base Models vs. Instruct Models) 我们需要理解的另一点是基础模型与指令模型的区别: - _基础模型 (Base Model)_ 是在原始文本数据上训练以预测下一个 token 的模型。 - _指令模型 (Instruct Model)_ 是专门微调以遵循指令并进行对话的模型。例如,`SmolLM2-135M`是一个基础模型,而`SmolLM2-135M-Instruct`是其指令调优变体。 要使基础模型表现得像指令模型,我们需要**以模型能够理解的一致方式格式化我们的提示**。这就是聊天模板的作用所在。 *ChatML*是一种这样的模板格式,它用清晰的角色指示符(系统、用户、助手)构建对话。如果你最近与一些 AI API 交互过,你就知道这是标准做法。 重要的是要注意,基础模型可以在不同的聊天模板上进行微调,所以当我们使用指令模型时,我们需要确保使用正确的聊天模板。 ### 理解聊天模板 (Understanding Chat Templates) 由于每个指令模型使用不同的对话格式和特 token,聊天模板的实现确保我们正确格式化提示,使其符合每个模型的期望。 在`transformers`中,聊天模板包含[Jinja2 代码](https://jinja.palletsprojects.com/en/stable/),描述如何将 ChatML 消息列表(如上面示例所示)转换为模型可以理解的系统级指令、用户消息和助手响应的文本表示。 这种结构**有助于保持交互的一致性,并确保模型对不同类型的输入做出适当响应**。 以下是`SmolLM2-135M-Instruct`聊天模板的简化版本: ```jinja2 {% for message in messages %} {% if loop.first and messages[0]['role'] != 'system' %} <|im_start|>system You are a helpful AI assistant named SmolLM, trained by Hugging Face <|im_end|> {% endif %} <|im_start|>{{ message['role'] }} {{ message['content'] }}<|im_end|> {% endfor %} ``` 如你所见,chat_template 描述了消息列表将如何被格式化。 给定这些消息: ```python messages = [ {"role": "system", "content": "You are a helpful assistant focused on technical topics."}, {"role": "user", "content": "Can you explain what a chat template is?"}, {"role": "assistant", "content": "A chat template structures conversations between users and AI models..."}, {"role": "user", "content": "How do I use it ?"}, ] ``` 前面的聊天模板将产生以下字符串: ```sh <|im_start|>system You are a helpful assistant focused on technical topics.<|im_end|> <|im_start|>user Can you explain what a chat template is?<|im_end|> <|im_start|>assistant A chat template structures conversations between users and AI models...<|im_end|> <|im_start|>user How do I use it ?<|im_end|> ``` `transformers`库会将聊天模板作为标记化过程的一部分为你处理。在这里阅读更多关于 transformers 如何使用聊天模板的信息。我们要做的就是以正确的方式构建我们的消息,标记器将处理剩下的事情。 你可以使用以下 Space 实验,看看同样的对话如何使用不同模型的相应聊天模板进行格式化: ### 消息到提示的转换 (Messages to prompt) 确保你的 LLM 正确接收格式化对话的最简单方法是使用模型标记器的`chat_template`。 ```python messages = [ {"role": "system", "content": "You are an AI assistant with access to various tools."}, {"role": "user", "content": "Hi !"}, {"role": "assistant", "content": "Hi human, what can help you with ?"}, ] ``` 要将前面的对话转换为提示,我们加载标记器并调用`apply_chat_template`: ```python from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM2-1.7B-Instruct") rendered_prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) ``` 这个函数返回的`rendered_prompt`现在可以作为你选择的模型的输入使用了! > 当你以 ChatML 格式与消息交互时,这个`apply_chat_template()`函数将在你的 API 后端使用。 现在我们已经看到 LLMs 如何通过聊天模板构建它们的输入,让我们探智能体如何在它们的环境中行动。 它们这样做的主要方式之一是使用工具 (Tools),这些工具扩展了 AI 模型在文本生成之外的能力。 我们将在接下来的单元中再次讨论消息,但如果你现在想深入了解,请查看: - Hugging Face 聊天模板指南 - Transformers 文档 ================================================ FILE: units/zh-CN/unit1/observations.mdx ================================================ # Observe: 整合反馈以反思和调整 Observations(观察)是**智能体感知其行动结果的方式**。 它们提供关键信息,为智能体的思考过程提供燃料并指导未来行动。 这些是**来自环境的信号**——无论是 API 返回的数据、错误信息还是系统日志——它们指导着下一轮的思考循环。 在观察阶段,智能体会: - **收集反馈**:接收数据或确认其行动是否成功 - **附加结果**:将新信息整合到现有上下文中,有效更新记忆 - **调整策略**:使用更新后的上下文来优化后续思考和行动 例如,当天气 API 返回数据*"partly cloudy, 15°C, 60% humidity"*(局部多云,15°C,60% 湿度)时,该观察结果会被附加到智能体的记忆(位于提示末尾)。 智能体随后利用这些信息决定是否需要额外数据,或是否准备好提供最终答案。 这种**迭代式反馈整合确保智能体始终保持与目标的动态对齐**,根据现实结果不断学习和调整。 这些观察**可能呈现多种形式**,从读取网页文本到监测机械臂位置。这可以视为工具"日志",为行动执行提供文本反馈。 | 观察类型 | 示例 | |---------------------|---------------------------------------------------------------------------| | 系统反馈 | 错误信息、成功通知、状态码 | | 数据变更 | 数据库更新、文件系统修改、状态变更 | | 环境数据 | 传感器读数、系统指标、资源使用情况 | | 响应分析 | API 响应、查询结果、计算输出 | | 基于时间的事件 | 截止时间到达、定时任务完成 | ## 结果如何被附加? 执行操作后,框架按以下步骤处理: 1. **解析操作** 以识别要调用的函数和使用的参数 2. **执行操作** 3. **将结果附加** 作为 **Observation** --- 至此我们已经学习了智能体的思考-行动-观察循环。 如果某些概念仍显模糊,不必担心——我们将在后续单元中重访并深化这些概念。 现在,是时候通过编写你的第一个智能体来实践所学知识了! ================================================ FILE: units/zh-CN/unit1/quiz1.mdx ================================================ # 小测验(不计分)[[quiz1]] 至此您已理解智能体的整体概念,包括其定义和工作原理。现在进行一个简短测验,因为**自我测试**是最佳学习方式,[可避免能力错觉](https://www.coursera.org/lecture/learning-how-to-learn/illusions-of-competence-BuFzf)。这将帮助您发现**需要加强的知识领域**。 本测验为可选项目,不计入评分。 ### 问题1:什么是智能体? 以下哪项最能描述AI智能体? --- ### 问题2:规划在智能体中的作用是什么? 为什么智能体在执行行动前需要进行规划? --- ### 问题3:工具如何增强智能体的能力? 为什么工具对智能体至关重要? --- ### 问题4:行动与工具有何区别? 行动和工具之间的关键差异是什么? --- ### 问题5:大语言模型(LLMs)在智能体中扮演什么角色? LLMs 如何支持智能体的功能实现? --- ### 问题6:以下哪个例子最能体现 AI 智能体? 哪个现实场景最能展示工作中的 AI 智能体? --- 恭喜完成测验 🥳!如果存在理解偏差,建议重读本章以巩固知识。若顺利通过,您已准备好深入探索"智能体大脑": LLMs。 ================================================ FILE: units/zh-CN/unit1/quiz2.mdx ================================================ # 快速自测(不计分)[[quiz2]] 什么?!还有测验?我们理解,我们理解... 😅 但这个简短的不计分测验旨在**帮助您巩固刚学习的关键概念**。 本测验涵盖大型语言模型(LLMs)、消息系统和工具——这些是理解和构建 AI 智能体的核心组件。 ### 问题1:以下哪项最能描述 AI 工具? --- ### 问题2: AI 智能体如何将工具作为"行动"在环境中使用? --- ### 问题3:什么是大语言模型(LLM)? --- ### 问题4:以下哪项最能描述特殊标记(special tokens)在 LLMs 中的作用? --- ### 问题5: AI 聊天模型如何处理用户消息的内部流程? --- 都明白了吗?很好!现在让我们**深入完整的智能体流程,开始构建你的第一个 AI 智能体!** ================================================ FILE: units/zh-CN/unit1/thoughts.mdx ================================================ # 思维机制:内部推理与 ReAct 方法 > [!TIP] > 本节将深入探讨 AI 智能体的内部运作机制——其推理与规划能力。我们将解析智能体如何通过内部对话分析信息,将复杂问题分解为可管理的步骤,并决策下一步行动。同时介绍 ReAct 方法,是一种鼓励模型在行动前"逐步思考"的提示技术。 思维(Thought)代表着智能体**解决任务的内部推理与规划过程**。 这利用了智能体的大型语言模型 (LLM) 能力**来分析其 prompt 中的信息**。 可将其视为智能体的内部对话,在此过程中它会考量当前任务并制定应对策略。 智能体的思维负责获取当前观察结果,并决定下一步应采取的行动。 通过这一过程,智能体能够**将复杂问题分解为更小、更易管理的步骤**,反思过往经验,并根据新信息持续调整计划。 以下是常见思维模式的示例: | 思维类型 | 示例 | |------------------|---------------------------------------------------------------------| | Planning(规划) | "I need to break this task into three steps: 1) gather data, 2) analyze trends, 3) generate report"("我需要将任务分解为三步:1)收集数据 2)分析趋势 3)生成报告") | | Analysis(分析) | "Based on the error message, the issue appears to be with the database connection parameters"("根据错误信息,问题似乎出在数据库连接参数") | | Decision Making(决策) | "Given the user's budget constraints, I should recommend the mid-tier option"("考虑到用户的预算限制,应推荐中端选项") | | Problem Solving(问题解决) | "To optimize this code, I should first profile it to identify bottlenecks"("优化此代码需先进行性能分析定位瓶颈") | | Memory Integration(记忆整合) | "The user mentioned their preference for Python earlier, so I'll provide examples in Python"("用户先前提到偏好 Python,因此我将提供 Python 示例") | | Self-Reflection(自我反思) | "My last approach didn't work well, I should try a different strategy"("上次方法效果不佳,应尝试不同策略") | | Goal Setting(目标设定) | "To complete this task, I need to first establish the acceptance criteria"("完成此任务需先确定验收标准") | | Prioritization(优先级排序) | "The security vulnerability should be addressed before adding new features"("在添加新功能前应先修复安全漏洞") | > **注意:** 对于专为 function-calling 微调的 LLMs,思维过程是可选的。 > *若您不熟悉 function-calling 概念,后续"行动"章节将提供详细说明。* ## ReAct 方法 核心方法是 **ReAct 方法**,即"推理"(Reasoning/Think)与"行动"(Acting/Act)的结合。 ReAct 是一种简单的提示技术,在让 LLM 解码后续 token 前添加"Let's think step by step"(让我们逐步思考)的提示。 通过提示模型"逐步思考",可以引导解码过程生成**计划**而非直接输出最终解决方案,因为模型被鼓励将问题**分解**为*子任务*。 这种方法使模型能够更详细地考虑各个子步骤,通常比直接生成最终方案产生更少错误。
ReAct
图 (d) 展示了 ReAct 方法示例,我们通过"Let's think step by step"提示模型
> [!TIP] > 近期推理策略受到广泛关注,这体现在 Deepseek R1 或 OpenAI 的 o1 等模型的开发中。这些模型经过微调,被训练为"先思考再回答"。 > > 它们通过特殊标记(`` 和 ``)来界定 _思考_ 部分。这不仅是类似 ReAct 的提示技巧,更是通过分析数千个示范案例,让模型学习生成这些思考段的训练方法。 --- 现在我们已经深入理解了思维过程,接下来将更深入探讨流程的第二部分:行动。 ================================================ FILE: units/zh-CN/unit1/tools.mdx ================================================ # 什么是工具? Unit 1 planning AI 智能体的关键能力在于执行**行动**。正如前文所述,这通过**工具**的使用实现。 本节将学习工具的定义、有效设计方法,以及如何通过系统消息将其集成到智能体中。 通过为智能体配备合适的工具——并清晰描述这些工具的工作原理——可显著提升 AI 的能力边界。让我们深入探讨! ## AI 工具的定义 **工具是赋予 LLM 的函数**,该函数应实现**明确的目标**。 以下是 AI 智能体中常用的工具示例: | 工具类型 | 描述 | |------------------|---------------------------------------------------------------| | 网络搜索 | 允许智能体从互联网获取最新信息 | | 图像生成 | 根据文本描述生成图像 | | 信息检索 | 从外部源检索信息 | | API 接口 | 与外部 API 交互(GitHub、YouTube、Spotify 等) | 以上仅为示例,实际可为任何用例创建工具! 优秀工具应能**补充 LLM 的核心能力**。 例如,若需执行算术运算,为 LLM 提供**计算器工具**将比依赖模型原生能力获得更好结果。 此外,**LLM 基于训练数据预测提示的补全**,意味着其内部知识仅包含训练截止前的信息。因此,若智能体需要最新数据,必须通过工具获取。 例如,若直接询问 LLM(无搜索工具)今日天气,LLM 可能会产生随机幻觉。 Weather - 合格工具应包含: - **函数功能的文本描述** - *可调用对象*(执行操作的实体) - 带类型声明的*参数* - (可选)带类型声明的输出 ## 工具如何运作? 正如前文所述,LLM 只能接收文本输入并生成文本输出。它们无法自行调用工具。当我们谈及_为智能体提供工具_时,实质是**教导** LLM 认识工具的存在,并要求模型在需要时生成调用工具的文本。例如,若我们提供从互联网获取某地天气的工具,当询问 LLM 巴黎天气时,LLM 将识别该问题适合使用我们教授的"天气"工具,并生成代码形式的文本来调用该工具。**智能体**负责解析 LLM 的输出,识别工具调用需求,并执行工具调用。工具的输出将返回给 LLM,由其生成最终用户响应。 工具调用的输出是对话中的另一种消息类型。工具调用步骤通常对用户不可见:智能体检索对话、调用工具、获取输出、将其作为新消息添加,并将更新后的对话再次发送给 LLM。从用户视角看,仿佛 LLM 直接使用了工具,但实际执行的是我们的应用代码(**智能体**)。 后续课程将深入探讨该流程。 ## 如何为 LLM 提供工具? 完整答案可能看似复杂,但核心是通过系统提示(system prompt)向模型文本化描述可用工具: System prompt for tools 为确保有效性,必须精准描述: 1. **工具功能** 2. **预期输入格式** 因此工具描述通常采用结构化表达方式(如编程语言或 JSON)。虽非强制,但任何精确、连贯的格式均可。 若觉抽象,我们通过具体示例理解。 我们将实现简化的**计算器**工具,仅执行两整数相乘。Python 实现如下: ```python def calculator(a: int, b: int) -> int: """Multiply two integers.""" return a * b ``` 因此我们的工具名为`calculator`,其功能是**将两个整数相乘**,需要以下输入: - **`a`**(*int*):整数 - **`b`**(*int*):整数 工具输出为另一个整数,描述如下: - (*int*):`a`与`b`的乘积 所有这些细节都至关重要。让我们将这些信息整合成 LLM 可理解的工具描述文本: ```text 工具名称: calculator,描述:将两个整数相乘。参数:a: int, b: int,输出:int ``` > **重要提示:** 此文本描述是*我们希望 LLM 了解的工具体系*。 当我们将上述字符串作为输入的一部分传递给 LLM 时,模型将识别其为工具,并知晓需要传递的输入参数及预期输出。 若需提供更多工具,必须保持格式一致性。此过程可能较为脆弱,容易遗漏某些细节。 是否有更好的方法? ### 自动化工具描述生成 我们的工具采用 Python 实现,其代码已包含所需全部信息: - 功能描述性名称:`calculator` - 详细说明(通过函数文档字符串实现):`将两个整数相乘` - 输入参数及类型:函数明确要求两个`int`类型参数 - 输出类型 这正是人们使用编程语言的原因:表达力强、简洁且精确。 虽然可以将 Python 源代码作为工具规范提供给 LLM,但具体实现方式并不重要。关键在于工具名称、功能描述、输入参数和输出类型。 我们将利用 Python 的**自省特性**,通过源代码自动构建工具描述。只需确保工具实现满足: 1. 使用类型注解(Type Hints) 2. 编写文档字符串(Docstrings) 3. 采用合理的函数命名 完成这些之后,我们只需使用一个 Python 装饰器来指示`calculator`函数是一个工具: ```python @tool def calculator(a: int, b: int) -> int: """Multiply two integers.""" return a * b print(calculator.to_string()) ``` 注意函数定义前的`@tool`装饰器。 通过我们即将看到的实现,可以利用装饰器提供的`to_string()`方法从源代码自动提取以下文本: ```text 工具名称: calculator,描述:将两个整数相乘。参数:a: int, b: int,输出:int ``` 正如所见,这与我们之前手动编写的内容完全一致! ### 通用工具类实现 我们创建通用`Tool`类,可在需要时重复使用: > **说明:** 此示例实现为虚构代码,但高度模拟了主流工具库的实际实现方式。 ```python class Tool: """ A class representing a reusable piece of code (Tool). Attributes: name (str): Name of the tool. description (str): A textual description of what the tool does. func (callable): The function this tool wraps. arguments (list): A list of argument. outputs (str or list): The return type(s) of the wrapped function. """ def __init__(self, name: str, description: str, func: callable, arguments: list, outputs: str): self.name = name self.description = description self.func = func self.arguments = arguments self.outputs = outputs def to_string(self) -> str: """ Return a string representation of the tool, including its name, description, arguments, and outputs. """ args_str = ", ".join([ f"{arg_name}: {arg_type}" for arg_name, arg_type in self.arguments ]) return ( f"Tool Name: {self.name}," f" Description: {self.description}," f" Arguments: {args_str}," f" Outputs: {self.outputs}" ) def __call__(self, *args, **kwargs): """ Invoke the underlying function (callable) with provided arguments. """ return self.func(*args, **kwargs) ``` 虽然看似复杂,但逐步解析即可理解其工作机制。我们定义的**`Tool`**类包含以下核心要素: - **`name`**(*str*):工具名称 - **`description`**(*str*):工具功能简述 - **`function`**(*callable*):工具执行的函数 - **`arguments`**(*list*):预期输入参数列表 - **`outputs`**(*str* 或 *list*):工具预期输出 - **`__call__()`**:调用工具实例时执行函数 - **`to_string()`**:将工具属性转换为文本描述 可通过如下代码创建工具实例: ```python calculator_tool = Tool( "calculator", # name "Multiply two integers.", # description calculator, # function to call [("a", "int"), ("b", "int")], # inputs (names and types) "int", # output ) ``` 但我们可以利用 Python 的`inspect`模块自动提取这些信息!这正是`@tool`装饰器的实现原理。 > 若感兴趣,可展开以下内容查看装饰器具体实现:
decorator code ```python def tool(func): """ A decorator that creates a Tool instance from the given function. """ # Get the function signature signature = inspect.signature(func) # Extract (param_name, param_annotation) pairs for inputs arguments = [] for param in signature.parameters.values(): annotation_name = ( param.annotation.__name__ if hasattr(param.annotation, '__name__') else str(param.annotation) ) arguments.append((param.name, annotation_name)) # Determine the return annotation return_annotation = signature.return_annotation if return_annotation is inspect._empty: outputs = "No return annotation" else: outputs = ( return_annotation.__name__ if hasattr(return_annotation, '__name__') else str(return_annotation) ) # Use the function's docstring as the description (default if None) description = func.__doc__ or "No description provided." # The function name becomes the Tool name name = func.__name__ # Return a new Tool instance return Tool( name=name, description=description, func=func, arguments=arguments, outputs=outputs ) ```
简而言之,在应用此装饰器后,我们可以按如下方式实现工具: ```python @tool def calculator(a: int, b: int) -> int: """Multiply two integers.""" return a * b print(calculator.to_string()) ``` 我们可以使用`Tool`类的`to_string`方法自动生成适合LLM使用的工具描述文本: ```text 工具名称: calculator,描述:将两个整数相乘。参数:a: int, b: int,输出:int ``` 该描述将被**注入**系统提示。以本节初始示例为例,替换`tools_description`后的系统提示如下: System prompt for tools 在[Actions](actions)章节,我们将深入探讨智能体如何**调用**刚创建的这个工具。 ### 模型上下文协议(MCP):统一的工具接口 模型上下文协议(MCP)是一种开放式协议,它规范了应用程序向 LLM 提工具的方式。 MCP 提供 - 不断增加的预构建集成列表,您的 LLM 可以直接接入这些集成 - 在 LLM 提供商和供应商之间灵活切换的能力 - 在基础设施内保护数据安全的最佳实践 这意味着任何实施 MCP 的框架都可以利用协议中定义的工具,从而无需为每个框架重新实现相同的工具接口。 --- 工具在增强AI智能体能力方面至关重要。 总结本节要点: - *工具定义*:通过提供清晰的文本描述、输入参数、输出结果及可调用函数 - *工具本质*:赋予LLM额外能力的函数(如执行计算或访问外部数据) - *工具必要性*:帮助智能体突破静态模型训练的局限,处理实时任务并执行专业操作 现在进入【智能体工作流】(agent-steps-and-structure)章节,您将看到智能体如何观察、思考与行动。这**整合了当前所学全部内容**,为创建功能完备的 AI 智能体奠定基础。 但在此之前,让我们先完成另一个简短测验! ================================================ FILE: units/zh-CN/unit1/tutorial.mdx ================================================ # 使用 smolagents 创建我们的第一个智能体 在上一节中,我们学习了如何使用 Python 代码从头开始创建智能体,并且我们**看到了这个过程是多么繁琐**。幸运的是,许多智能体库通过**为你处理大量繁重的工作**来简化这项工作。 在本教程中,**你将创建你的第一个智能体**,它能够执行图像生成、网络搜索、时区检查等更多操作! 你还将把你的智能体**发布到 Hugging Face Space 上,以便与朋友和同事分享**。 让我们开始吧! ## 什么是 smolagents? smolagents 为了创建这个智能体,我们将使用 `smolagents`,这是一个**提供轻松开发智能体框架的库**。 这个轻量级库设计简洁,但它抽象了构建智能体的许多复杂性,使你能够专注于设计智能体的行为。 我们将在下一个单元中深入了解 smolagents。同时,你也可以查看这篇博客文章或该库的GitHub 仓库。 简而言之,`smolagents` 是一个专注于 **codeAgent** 的库,codeAgent 是一种通过代码块执行**“操作”**,然后通过执行代码**“观察”**结果的智能体。 以下是我们将构建的一个示例! 我们为我们的智能体提供了一个**图像生成工具**,并要求它生成一张猫的图片。 `smolagents` 中的智能体将具有**与我们之前构建的自定义智能体相同的行为**:它将**以循环的方式思考、行动和观察**,直到得出最终答案: 很令人兴奋,对吧? ## 让我们来构建我们的智能体! 首先,复制这个 Space:https://huggingface.co/spaces/agents-course/First_agent_template > 感谢 Aymeric 提供的这个模板!🙌 复制这个 Space 意味着**在你的个人资料中创建一个本地副本**: 复制 复制这个 Space 之后,**你需要添加你的 Hugging Face API token**,以便你的**智能体**可以调用模型 API。 1. 首先,从[ https://hf.co/settings/tokens ](https://hf.co/settings/tokens)获取一个具有**推理权限**的 token,第 4 步需要用到。如果你已经有了,可以跳过此步。 2. 进入你的主页,找到刚才复制的空间,点击**设置**按钮。 3. 向下滚动到**变量和密钥**部分,点击**新建密钥**。 4. 创建一个名为**HF_TOKEN**的密钥,值为第一步获取到的 token。 5. 点击**保存**。 在整个课程中,你唯一需要修改的文件是当前不完整的**"app.py"**。你可以在这里查看[模板中的原始文件](https://huggingface.co/spaces/agents-course/First_agent_template/blob/main/app.py)。要找到你的文件,请进入你复制的 Space,然后点击 `Files` 选项卡,再在目录列表中点击 `app.py`。 让我们一起分解代码: - 文件开头是一些简单但必要的库导入 ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel, load_tool, tool import datetime import requests import pytz import yaml from tools.final_answer import FinalAnswerTool ``` 正如之前所述,我们将直接使用 **smolagents** 中的 **CodeAgent** 类。 ### Tool(工具) 现在让我们来了解一下工具!如果你需要回顾一下工具的相关内容,请随时回到课程的[工具](tools)部分。 ```python @tool def my_custom_tool(arg1:str, arg2:int)-> str: # it's important to specify the return type # Keep this format for the tool description / args description but feel free to modify the tool """A tool that does nothing yet Args: arg1: the first argument arg2: the second argument """ return "What magic will you build ?" @tool def get_current_time_in_timezone(timezone: str) -> str: """A tool that fetches the current local time in a specified timezone. Args: timezone: A string representing a valid timezone (e.g., 'America/New_York'). """ try: # Create timezone object tz = pytz.timezone(timezone) # Get current time in that timezone local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S") return f"The current local time in {timezone} is: {local_time}" except Exception as e: return f"Error fetching time for timezone '{timezone}': {str(e)}" ``` 这些工具是我们在这个部分鼓励你构建的东西!我们给你两个例子: 1. 一个**不工作的虚拟工具**,你可以修改它来制作一些有用的东西。 2. 一个**实际工作的工具**,它可以获取世界某地的当前时间。 要定义你的工具,重要的是: 1. 为你的函数提供输入和输出类型,例如 `get_current_time_in_timezone(timezone: str) -> str:` 2. **格式良好的文档字符串**。`smolagents` 期望所有参数在文档字符串中都有**文字描述**。 ### The Agent(智能体) 它使用 [`Qwen/Qwen2.5-Coder-32B-Instruct`](https://huggingface.co/Qwen/Qwen2.5-Coder-32B-Instruct) 作为 LLM 引擎。这是一个非常强大的模型,我们将通过无服务器 API 访问它。 ```python final_answer = FinalAnswerTool() model = InferenceClientModel( max_tokens=2096, temperature=0.5, model_id='Qwen/Qwen2.5-Coder-32B-Instruct', custom_role_conversions=None, ) with open("prompts.yaml", 'r') as stream: prompt_templates = yaml.safe_load(stream) # We're creating our CodeAgent agent = CodeAgent( model=model, tools=[final_answer], # add your tools here (don't remove final_answer) max_steps=6, verbosity_level=1, grammar=None, planning_interval=None, name=None, description=None, prompt_templates=prompt_templates ) GradioUI(agent).launch() ``` 这个智能体仍在使用我们在前面部分中看到的`InferenceClient`,它位于**InferenceClientModel**类的背后! 当我们介绍 Unit 2 中的框架时,我们会给出更深入的例子。目前,你需要专注于通过智能体的`tools`参数**向工具列表中添加新工具**。 例如,你可以使用代码第一行导入的`DuckDuckGoSearchTool`,或者你可以检查稍后从 Hub 加载的`image_generation_tool`。 **添加工具将赋予你的智能体新的能力**,在这里尝试发挥创意吧! 完整的"app.py": ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel, load_tool, tool import datetime import requests import pytz import yaml from tools.final_answer import FinalAnswerTool from Gradio_UI import GradioUI # Below is an example of a tool that does nothing. Amaze us with your creativity! @tool def my_custom_tool(arg1:str, arg2:int)-> str: # it's important to specify the return type # Keep this format for the tool description / args description but feel free to modify the tool """A tool that does nothing yet Args: arg1: the first argument arg2: the second argument """ return "What magic will you build ?" @tool def get_current_time_in_timezone(timezone: str) -> str: """A tool that fetches the current local time in a specified timezone. Args: timezone: A string representing a valid timezone (e.g., 'America/New_York'). """ try: # Create timezone object tz = pytz.timezone(timezone) # Get current time in that timezone local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S") return f"The current local time in {timezone} is: {local_time}" except Exception as e: return f"Error fetching time for timezone '{timezone}': {str(e)}" final_answer = FinalAnswerTool() model = InferenceClientModel( max_tokens=2096, temperature=0.5, model_id='Qwen/Qwen2.5-Coder-32B-Instruct', custom_role_conversions=None, ) # Import tool from Hub image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True) with open("prompts.yaml", 'r') as stream: prompt_templates = yaml.safe_load(stream) agent = CodeAgent( model=model, tools=[final_answer], # add your tools here (don't remove final_answer) max_steps=6, verbosity_level=1, grammar=None, planning_interval=None, name=None, description=None, prompt_templates=prompt_templates ) GradioUI(agent).launch() ``` 你的**目标**是熟悉 Space 和智能体。 目前,模板中的智能体**没有使用任何工具,所以尝试为它提供一些预制的工具,甚至自己动手制作一些新工具!** 我们非常期待在 Discord 频道 **#agents-course-showcase** 中看到你的精彩智能体成果! --- 恭喜你,你已经构建了你的第一个智能体!不要犹豫,与你的朋友和同事分享吧。 由于这是你的第一次尝试,如果有点小问题或速度有点慢,这是完全正常的。在未来的单元中,我们将学习如何构建更好的智能体。 最好的学习方法是尝试,所以不要犹豫,去更新它,添加更多工具,尝试使用另一个模型,等等。 在下一节中,你将完成最后的测验并获得证书! ================================================ FILE: units/zh-CN/unit1/what-are-agents.mdx ================================================ # 什么是智能体? 第一单元规划 在本节结束时,你将对智能体的概念及其在人工智能中的各种应用感到熟悉。 为了解释什么是智能体,我们先从一个类比开始。 ## 整体概览:智能体 Alfred 来见见 Alfred。Alfred 是一个**智能体**。 这是 Alfred 想象 Alfred **收到一个指令**,比如:“Alfred,我想来杯咖啡。” 我想来杯咖啡 因为 Alfred **理解自然语言**,他很快就明白了我们的请求。 在完成任务之前,Alfred 会进行**推理和规划**,弄清楚他需要的步骤和工具: 1. 去厨房 2. 使用咖啡机 3. 煮咖啡 4. 把咖啡拿回来 推理和规划 一旦有了计划,他就**必须行动**。为了执行计划,**他可以使用他所知道的工具列表中的工具**。 在这个例子中,为了煮咖啡,他使用了咖啡机。他启动咖啡机来煮咖啡。 煮咖啡 最后,Alfred 把刚煮好的咖啡拿给我们。 拿咖啡 这就是智能体:一个**能够进行推理、规划和与环境交互的人工智能模型**。 我们称之为智能体,因为它具有**能动性**,即与环境交互的能力。 智能体过程 ## 更正式的定义 现在你已经了解了整体情况,以下是一个更精确的定义: > 智能体是一个系统,它利用人工智能模型与环境交互,以实现用户定义的目标。它结合推理、规划和动作执行(通常通过外部工具)来完成任务。 可以把智能体想象成有两个主要部分: 1. **大脑(AI 模型)** 这是所有思考发生的地方。AI 模型**负责推理和规划**。它根据情况决定**采取哪些行动**。 2. **身体(能力和工具)** 这部分代表了**智能体所能做的一切**。 **可能行动的范围**取决于智能体**被配备了什么**。例如,因为人类没有翅膀,所以他们不能执行“飞”这个**行动**,但他们可以执行“走”、“跑”、“跳”、“抓”等**行动**。 ### “智能体”能力的层次 根据上述定义,智能体的能力递增可视为一个连续谱系: | 智能体等级 | 描述 | 常见称谓 | 示例模式 | | --- | --- | --- | --- | | ☆☆☆ | 智能体输出不影响程序流程 | 简单处理器 | `processllmoutput(llmresponse)` | | ★☆☆ | 智能体输出决定基本控制流 | 路由 | `if llmdecision(): patha() else: pathb()` | | ★★☆ | 智能体输出决定函数调用 | 函数调用者 | `runfunction(llmchosentool, llmchosenargs)` | | ★★★ | 智能体输出控制迭代及程序延续 | 多步智能体 | `while llmshouldcontinue(): executenextstep()` | | ★★★ | 一个智能体流程可启动另一个智能体流程 | 多智能体系统 | `if llmtrigger(): executeagent()` | 表格摘自[smolagents概念指南](https://huggingface.co/docs/smolagents/conceptualguides/intro_agents)。 ## 我们为智能体使用什么类型的 AI 模型? 智能体中最常见的 AI 模型是 LLM(大型语言模型),它接受**文本**作为输入,并输出**文本**。 知名的例子包括**OpenAI** 的 **GPT4**、**Meta** 的 **LLama**、**Google** 的 **Gemini** 等。这些模型已经经过大量文本的训练,并且具有很好的泛化能力。我们将在[下一节](what-are-llms)中更深入地了解 LLM。 > [!TIP] > 也可以使用接受其他输入作为智能体核心模型的模型。例如,视觉语言模型(VLM),它就像 LLM 一样,但也能理解图像作为输入。我们现在将重点关注 LLM,稍后再讨论其他选项。 ## AI 如何在环境中采取行动? LLM 是令人惊叹的模型,但**它们只能生成文本**。 然而,如果你让像 HuggingChat 或 ChatGPT 这样的知名聊天应用程序生成图像,它们却可以做到!这是怎么可能的? 答案是,HuggingChat、ChatGPT 和类似应用程序的开发者实现了额外的功能(称为**工具**),LLM 可以利用这些工具来创建图像。
埃菲尔铁塔与西兰花
模型使用图像生成工具生成了这张图像。
我们将在[工具](tools)一节中更深入地了解工具。 ## 智能体可以执行什么类型的任务? 智能体可以通过**工具**执行我们实现的任何任务来完成**行动**。 例如,如果我编写一个智能体作为我电脑上的个人助理(像 Siri 一样),并且我让它“给我的经理发一封邮件,要求推迟今天的会议”,我可以给它一些发送邮件的代码。这将是一个新的工具,智能体在需要发送邮件时可以随时使用。我们可以用 Python 编写它: ```python def send_message_to(recipient, message): """Useful to send an e-mail message to a recipient""" ... ``` 如我们所见,大型语言模型(LLM)将在需要时生成运行该工具的代码,从而完成所需任务。 ```python send_message_to("Manager", "Can we postpone today's meeting?") ``` **工具的设计至关重要,对智能体的质量有着深远的影响**。某些任务可能需要定制特定的工具,而其他任务则可以通过通用工具(如“网络搜索”)来解决。 > 请注意,**动作(Actions)与工具(Tools)是不同的概念**。例如,一个动作可能涉及使用多个工具来完成任务。 允许智能体与其环境进行交互**为企业和个人提供了实际应用场景**。 ### 示例 1:个人虚拟助手 像 Siri、Alexa 或 Google Assistant 这样的虚拟助手,在代表用户与其数字环境交互时,充当着智能体的角色。 它们接收用户查询,分析上下文,从数据库中检索信息,并提供响应或启动动作(如设置提醒、发送消息或控制智能设备)。 ### 示例 2:客户服务聊天机器人 许多公司部署聊天机器人作为智能体,使其能够以自然语言与客户互动。 这些智能体可以回答问题、引导用户完成故障排除步骤、在内部数据库中创建问题,甚至完成交易。 它们的预定义目标可能包括提高用户满意度、减少等待时间或提高销售转化率。通过直接与客户互动、从对话中学习并随着时间的推移调整其响应,它们展示了智能体的核心原理。 ### 示例 3:视频游戏中的 AI 非玩家角色(NPC) 基于大语言模型(LLMs)的智能体可以使非玩家角色(NPC)更具动态性和不可预测性。 它们不再局限于僵化的行为树,而是能够**根据上下文做出响应、适应玩家交互**,并生成更细致入微的对话。这种灵活性有助于创造更生动、更具吸引力的角色,这些角色会随着玩家的操作而发展。 --- 总结而言,智能体是一个系统,它使用人工智能模型(通常是大语言模型)作为其核心推理引擎,以实现以下功能: - **理解自然语言**:以有意义的方式解释和回应人类指令。 - **推理与规划**:分析信息、做出决策并制定解决问题的策略。 - **与环境交互**:收集信息、执行操作并观察这些操作的结果。 现在你已经对智能体有了扎实的理解,让我们通过一个简短的、不计分的测验来巩固你的知识。之后,我们将深入探讨智能体的“大脑”:[大型语言模型(LLM)](what-are-llms)。 ================================================ FILE: units/zh-CN/unit1/what-are-llms.mdx ================================================ # 什么是大语言模型(LLMs)? Unit 1 planning 在上一节中,我们了解到每个智能体都需要一个核心的人工智能模型,而大语言模型 (LLM) 是实现这一目标最常见的 AI 模型类型。 现在,我们将学习什么是大语言模型,以及它们如何为智能体提供动力。 本节将提供一个简洁的技术解释,说明大语言模型的用途。如果你想更深入地了解相关内容,可以参考我们的 免费自然语言处理课程。 ## 什么是大语言模型? 大语言模型 (LLM) 是一种擅长理解和生成人类语言的人工智能模型。它们通过大量文本数据的训练,能够学习语言中的模式、结构,甚至细微差别。这些模型通常包含数千万甚至更多的参数。 如今,大多数大语言模型都是基于 Transformer 架构构建的 —— 这是一种基于“注意力”算法的深度学习架构。自 2018 年 Google 推出 BERT 以来,这种架构引起了广泛关注。
Transformer
原始的 Transformer 架构如下所示,左侧是编码器(encoder),右侧是解码器(decoder)。
Transformer 有三种类型: 1. **编码器(Encoders)** 基于编码器的 Transformer 接收文本(或其他数据)作为输入,并输出该文本的密集表示(或嵌入)。 - **示例**:Google 的 BERT - **用例**:文本分类、语义搜索、命名实体识别 - **典型规模**:数百万个参数 2. **解码器(Decoders)** 基于解码器的 Transformer 专注于**逐个生成 token 以完成序列**。 - **示例**:Meta 的 Llama - **用例**:文本生成、聊天机器人、代码生成 - **典型规模**:数十亿(按美国用法,即 10^9)个参数 3. **序列到序列(编码器-解码器,Seq2Seq(Encoder–Decoder))** 序列到序列的 Transformer *结合*了编码器和解码器。编码器首先将输入序列处理成上下文表示,然后解码器生成输出序列。 - **示例**:T5、BART - **用例**:翻译、摘要、改写 - **典型规模**:数百万个参数 虽然大语言模型 (LLMs) 有多种形式,但它们通常是基于解码器的模型,拥有数十亿个参数。以下是一些最知名的大语言模型: | **模型** | **提供商** | | --------------- | ---------------------------- | | **Deepseek-R1** | DeepSeek | | **GPT4** | OpenAI | | **Llama 3** | Meta(Facebook AI Research) | | **SmolLM2** | Hugging Face | | **Gemma** | Google | | **Mistral** | Mistral | 大语言模型 (LLM) 的基本原理简单却极其有效:**其目标是在给定一系列前一个 token 的情况下,预测下一个 token**。这里的“token”是 LLM 处理信息的基本单位。你可以把 “token”想象成“单词”,但出于效率考虑,LLM 并不直接使用整个单词。 例如,虽然英语估计有 60 万个单词,但一个 LLM 的词汇表可能只有大约 32,000 个 token(如 Llama 2 的情况)。Tokenization 通常作用于可以组合的子词单元。 举个例子,考虑如何将 token“interest”和“ing”组合成“interesting”,或者添加“ed”形成“interested”。 你可以在下面的交互式游乐场中尝试不同的 tokenizer 来实验: 每个大语言模型 (LLM) 都有一些特定于该模型的**特殊 token**。LLM 使用这些 token 来开启和关闭其生成过程中的结构化组件。例如,用于指示序列、消息或响应的开始或结束。此外,我们传递给模型的输入提示也使用特殊 token 进行结构化。其中最重要的是**序列结束 token** (EOS,End of Sequence token)。 不同模型提供商使用的特殊 token 形式差异很大。 下表展示了特殊 token 的多样性:
Model Provider EOS Token Functionality
GPT4 OpenAI <|endoftext|> End of message text
Llama 3 Meta (Facebook AI Research) <|eot_id|> End of sequence
Deepseek-R1 DeepSeek <|end_of_sentence|> End of message text
SmolLM2 Hugging Face <|im_end|> End of instruction or message
Gemma Google <end_of_turn> End of conversation turn
> [!TIP] > 我们并不期望你记住这些特 token,但重要的是要理解它们的多样性以及它们在大语言模型 (LLM) 文本生成中所扮演的角色。如果你想了解更多关于特殊 token 的信息,可以查看模型在其 Hub 仓库中的配置。例如,你可以在[SmolLM2 模型的 tokenizer_config.json 文件](https://huggingface.co/HuggingFaceTB/SmolLM2-135M-Instruct/blob/main/tokenizer_config.json)中找到该模型的特殊 token。 ## 理解下一个词元预测 大语言模型 (LLM) 被认为是**自回归**的,这意味着**一次通过的输出成为下一次的输入**。这个循环持续进行,直到模型预测下一个词元为 EOS(结束符)词元,此时模型可以停止。 自回归解码的视觉 GIF 图 换句话说,LLM 会解码文本,直到达到 EOS。但在单个解码循环中会发生什么? 虽然对于学习智能体而言,整个过程可能相当技术化,但以下是简要概述: - 一旦输入文本被**词元化**,模型就会计算序列的表示,该表示捕获输入序列中每个词元的意义和位置信息。 - 这个表示被输入到模型中,模型输出分数,这些分数对词汇表中每个词元作为序列中下一个词元的可能性进行排名。 解码的视觉 GIF 图 基于这些分数,我们有多种策略来选择词元以完成句子。 - 最简单的解码策略是总是选择分数最高的词元。 您可以在此 Space 中使用 SmolLM2 自己与解码过程进行交互(记住,它会一直解码,直到达到 **EOS** 词元,对于这个模型来说,EOS 词元是**<|im_end|>**): - 但还有更先进的解码策略。例如, _束搜索(beam search)_ 会探索多个候选序列,以找到总分数最高的序列——即使其中一些单个词元的分数较低。 如果你想了解更多关于解码的信息,可以查看[NLP 课程](https://huggingface.co/learn/nlp-course)。 ## 注意力机制就是你的全部所需 Transformer 架构的一个关键方面是**注意力机制**。在预测下一个词时,句子中的每个词并不是同等重要的;例如,在句子 _“The capital of France is ...”_ 中,“France” 和 “capital” 这样的词携带了最多的意义。 注意力机制的视觉 GIF 图 这种识别最相关词以预测下一个词元的过程已被证明是非常有效的。 尽管自 GPT-2 以来,大语言模型(LLM)的基本原理——预测下一个词元——一直保持不变,但在扩展神经网络以及使注意力机制能够处理越来越长的序列方面已经取得了显著进展。 如果你与大语言模型交互过,你可能对*上下文长度*这个术语很熟悉,它指的是大语言模型能够处理的最大词元数,以及其最大的*注意力跨度*。 ## 提示大语言模型很重要 考虑到大语言模型(LLM)的唯一工作是通过查看每个输入词元来预测下一个词元,并选择哪些词元是“重要的”,因此你提供的输入序列的措辞非常重要。 你提供给大语言模型的输入序列被称为*提示*。精心设计提示可以更容易地**引导大语言模型的生成朝着期望的输出方向进行**。 ## 大语言模型是如何训练的? 大语言模型是在大型文本数据集上进行训练的,它们通过自监督或掩码语言建模目标来学习预测序列中的下一个词。 通过这种无监督学习,模型学习了语言的结构以及**文本中的潜在模式,使模型能够泛化到未见过的数据**。 在这个初始的*预训练*之后,大语言模型可以在监督学习目标上进行微调,以执行特定任务。例如,一些模型被训练用于对话结构或工具使用,而其他模型则专注于分类或代码生成。 ## 我如何使用大语言模型? 你有两个主要选择: 1. **本地运行**(如果你有足够的硬件资源)。 2. **使用云服务/API**(例如,通过 Hugging Face 的无服务器推理 API)。 在本课程中,我们将主要通过 Hugging Face Hub 上的 API 使用模型。稍后,我们将探讨如何在你的本地硬件上运行这些模型。 ## 大语言模型在 AI 智能体中是如何使用的? 大语言模型是 AI 智能体的关键组件,**为理解和生成人类语言提供了基础**。 它们可以解释用户指令,在对话中保持上下文,制定计划并决定使用哪些工具。 我们将在本单元中更详细地探讨这些步骤,但现在你需要理解的是,大语言模型是**智能体的大脑**。 --- 那信息量可真不小!我们已经涵盖了大语言模型(LLM)的基本概念、工作原理以及它们在驱动 AI 智能体中的作用。 如果你想更深入地探索语言模型和自然语言处理这个迷人的世界,不妨查看我们的免费 NLP 课程。 现在我们已经了解了大语言模型的工作原理,接下来是时候看看**大语言模型如何在对话语境中构建其生成内容**了。 要运行这个笔记本,**你需要一个 Hugging Face token**,你可以从 https://hf.co/settings/tokens 获取。 有关如何运行 Jupyter Notebook 的更多信息,请查看 Hugging Face Hub 上的 Jupyter Notebook。 你还需要请求访问 Meta Llama 模型。 ================================================ FILE: units/zh-CN/unit2/introduction.mdx ================================================ # 智能体框架介绍 Thumbnail 欢迎来到第二单元,在这里**我们将探索不同的智能体框架(agentic frameworks)**,这些框架可用于构建强大的智能体应用。 我们将学习: - 在单元 2.1:[smolagents](https://huggingface.co/docs/smolagents/en/index) - 在单元 2.2:[LlamaIndex](https://www.llamaindex.ai/) - 在单元 2.3:[LangGraph](https://www.langchain.com/langgraph) 让我们开始吧!🕵 ## 何时使用智能体框架 **构建围绕大语言模型(LLMs)的应用时,并不总是需要智能体框架**。它们在工作流中提供了灵活性,可以高效地解决特定任务,但并非总是必需的。 有时,**预定义的工作流足以满足用户请求**,并且没有真正需要智能体框架。如果构建智能体的方法很简单,比如一系列提示,使用纯代码可能就足够了。优势在于开发者将**完全控制和理解他们的系统,没有抽象层**。 然而,当工作流变得更加复杂时,例如让大语言模型调用函数或使用多个智能体,这些抽象开始变得有用。 考虑到这些想法,我们已经可以确定对一些功能的需求: * 一个驱动系统的*大语言模型引擎*。 * 智能体可以访问的*工具列表*。 * 用于从大语言模型输出中提取工具调用的*解析器*。 * 与解析器同步的*系统提示*。 * 一个*记忆系统*。 * *错误日志和重试机制*以控制大语言模型的错误。 我们将探讨这些主题在各种框架中如何解决,包括 `smolagents`、`LlamaIndex` 和 `LangGraph`。 ## 智能体框架单元 | 框架 | 描述 | 单元作者 | |------------|----------------|----------------| | [smolagents](./smolagents/introduction) | 由 Hugging Face 开发的智能体框架。 | Sergio Paniego - [HF](https://huggingface.co/sergiopaniego) - [X](https://x.com/sergiopaniego) - [Linkedin](https://www.linkedin.com/in/sergio-paniego-blanco) | | [Llama-Index](./llama-index/introduction) | 将上下文增强智能体带至生产端的端到端工具 | David Berenstein - [HF](https://huggingface.co/davidberenstein1957) - [X](https://x.com/davidberenstei) - [Linkedin](https://www.linkedin.com/in/davidberenstein) | | [LangGraph](./langgraph/introduction) | 允许对智能体进行有序协调的智能体 | Joffrey THOMAS - [HF](https://huggingface.co/Jofthomas) - [X](https://x.com/Jthmas404) - [Linkedin](https://www.linkedin.com/in/joffrey-thomas) | ================================================ FILE: units/zh-CN/unit2/langgraph/building_blocks.mdx ================================================ # LangGraph 的核心构建模块 要使用 LangGraph 构建应用程序,需要理解其核心组件。让我们探索构成 LangGraph 应用程序的基础构建模块。 Building Blocks LangGraph 应用程序从 **entrypoint** 开始,根据执行情况,流程可能流向不同的函数直到抵达 END。 Application ## 1. 状态(State) **State** 是 LangGraph 中的核心概念,表示流经应用程序的所有信息。 ```python from typing_extensions import TypedDict class State(TypedDict): graph_state: str ``` 状态是 **用户自定义** 的,因此需要仔细设计字段以包含决策过程所需的所有数据! > 💡 **提示:** 仔细考虑应用程序需要在步骤之间跟踪哪些信息。 ## 2. 节点(Nodes) **Nodes** 是 Python 函数。每个节点: - 接收状态作为输入 - 执行某些操作 - 返回状态更新 ```python def node_1(state): print("---Node 1---") return {"graph_state": state['graph_state'] +" I am"} def node_2(state): print("---Node 2---") return {"graph_state": state['graph_state'] +" happy!"} def node_3(state): print("---Node 3---") return {"graph_state": state['graph_state'] +" sad!"} ``` 举例, 节点可以包含: - **LLM 调用**: 生成文本或做出决策 - **工具调用**: 与外部系统交互 - **条件逻辑**: 决定后续步骤 - **人工干预**: 获取用户输入 > 💡 **信息:** 像 START 和 END 这样的必要节点已直接包含在 LangGraph 中。 ## 3. 边(Edges) **Edges** 连接节点并定义图中的可能路径: ```python import random from typing import Literal def decide_mood(state) -> Literal["node_2", "node_3"]: # 通常我们会根据状态决定下一个节点 user_input = state['graph_state'] # 这里我们在节点2和节点3之间简单实现 50/50 的概率分配 if random.random() < 0.5: # 50% 时间, 我们返回节点2 return "node_2" # 50% 时间, 我们返回节点3 return "node_3" ``` 边可以是: - **直接边**: 始终从节点 A 到节点 B - **条件边**: 根据当前状态选择下一个节点 ## 4. 状态图(StateGraph) **StateGraph** 是包含整个 agent 工作流的容器: ```python from IPython.display import Image, display from langgraph.graph import StateGraph, START, END # 构建图表 builder = StateGraph(State) builder.add_node("node_1", node_1) builder.add_node("node_2", node_2) builder.add_node("node_3", node_3) # 连接逻辑 builder.add_edge(START, "node_1") builder.add_conditional_edges("node_1", decide_mood) builder.add_edge("node_2", END) builder.add_edge("node_3", END) # 编译 graph = builder.compile() ``` 可以可视化图表: ```python # 可视化 display(Image(graph.get_graph().draw_mermaid_png())) ``` 图可视化 最重要的是可以调用: ```python graph.invoke({"graph_state" : "Hi, this is Lance."}) ``` output : ``` ---Node 1--- ---Node 3--- {'graph_state': 'Hi, this is Lance. I am sad!'} ``` ## 下一步? 下一节我们将通过构建第一个图表来实践这些概念。该图表将让 Alfred 能够处理电子邮件,进行分类,并在邮件真实时起草初步回复。 ================================================ FILE: units/zh-CN/unit2/langgraph/conclusion.mdx ================================================ # 结语 祝贺您完成了第二单元的 `LangGraph` 模块!🥳 您现在已经掌握了使用 LangGraph 构建结构化工作流的基础知识,这些工作流可以直接投入生产环境。 本模块只是您 LangGraph 学习之旅的起点。对于更深入的学习内容,我们推荐: - 探索 [LangGraph 官方文档](https://github.com/langchain-ai/langgraph) - 参加 LangChain Academy 的 [LangGraph 入门课程](https://academy.langchain.com/courses/intro-to-langgraph) - 亲自构建一些项目! 在下一个单元中,您将探索真实的应用场景。是时候将理论付诸实践了! 我们非常重视 **您对课程的想法和改进建议**。如果有任何反馈,请👉[填写此表单](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ### 持续学习,保持激情!🤗 尊敬的先生/女士!🎩🦇 -Alfred- ================================================ FILE: units/zh-CN/unit2/langgraph/document_analysis_agent.mdx ================================================ # 文档分析图 Alfred 为您服务。作为韦恩先生值得信赖的管家,我已记录下协助处理各类文档需求的工作流程。当 Mr Wayne 外出进行...夜间活动时,我会确保所有文件、训练计划和营养方案都得到妥善分析和整理。 在离开前,他留下了本周训练计划的笔记。我随后负责拟定了明日餐点的**菜单**。 为应对未来的类似需求,让我们使用 LangGraph 构建一个文档分析系统来服务 Mr Wayne。该系统能够: 1. 处理图像文档 2. 使用视觉模型 (Vision Language Model) 提取文本 3. 在需要时执行计算(用于演示常规工具) 4. 分析内容并提供简明摘要 5. 执行与文档相关的特定指令 ## 管家的工作流程 我们将构建的工作流程遵循以下结构化方案: ![Butler's Document Analysis Workflow](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/LangGraph/alfred_flow.png) > [!TIP] > 您可以在 这个 notebook 中查看代码,并通过 Google Colab 运行。 ## 设置环境 ```python %pip install langgraph langchain_openai Pillow base64 langchain_core ``` and imports : ```python import base64 from typing import List, TypedDict, Annotated, Optional from langchain.schema import HumanMessage from langchain_openai import ChatOpenAI from langchain_core.messages import AnyMessage, SystemMessage from langgraph.graph.message import add_messages from langgraph.graph import START, StateGraph from langgraph.prebuilt import tools_condition from langgraph.prebuilt import ToolNode from IPython.display import Image, display ``` ## 定义智能体的状态 这个状态比我们之前见过的稍微复杂些。 AnyMessage 是来自 langchain 的类,用于定义消息,而 add_messages 是一个操作符,它会添加最新消息而不是覆盖现有状态。 这是 langGraph 中的一个新概念,您可以在状态中添加 operators 来定义它们之间的交互方式。 ```python class AgentState(TypedDict): # 提供的文件 input_file: Optional[str] # Contains file path (PDF/PNG) messages: Annotated[list[AnyMessage], add_messages] ``` ## 准备工具 ```python vision_llm = ChatOpenAI(model="gpt-4o") def extract_text(img_path: str) -> str: """ Extract text from an image file using a multimodal model. Master Wayne often leaves notes with his training regimen or meal plans. This allows me to properly analyze the contents. """ all_text = "" try: # 读取图像并编码为 base64 with open(img_path, "rb") as image_file: image_bytes = image_file.read() image_base64 = base64.b64encode(image_bytes).decode("utf-8") # 准备包含 base64 图像数据的提示 message = [ HumanMessage( content=[ { "type": "text", "text": ( "Extract all the text from this image. " "Return only the extracted text, no explanations." ), }, { "type": "image_url", "image_url": { "url": f"data:image/png;base64,{image_base64}" }, }, ] ) ] # 调用具有视觉功能的模型 response = vision_llm.invoke(message) # 附加提取的文本 all_text += response.content + "\n\n" return all_text.strip() except Exception as e: # 管家应优雅地处理错误 error_msg = f"Error extracting text: {str(e)}" print(error_msg) return "" def divide(a: int, b: int) -> float: """Divide a and b - for Master Wayne's occasional calculations.""" return a / b # 为管家配备工具 tools = [ divide, extract_text ] llm = ChatOpenAI(model="gpt-4o") llm_with_tools = llm.bind_tools(tools, parallel_tool_calls=False) ``` ## 节点 ```python def assistant(state: AgentState): # 系统消息 textual_description_of_tool=""" extract_text(img_path: str) -> str: Extract text from an image file using a multimodal model. Args: img_path: A local image file path (strings). Returns: A single string containing the concatenated text extracted from each image. divide(a: int, b: int) -> float: Divide a and b """ image=state["input_file"] sys_msg = SystemMessage(content=f"You are an helpful butler named Alfred that serves Mr. Wayne and Batman. You can analyse documents and run computations with provided tools:\n{textual_description_of_tool} \n You have access to some optional images. Currently the loaded image is: {image}") return { "messages": [llm_with_tools.invoke([sys_msg] + state["messages"])], "input_file": state["input_file"] } ``` ## ReAct 模式:我如何协助 Wayne 先生 请允许我解释该智能体的工作方式。该智能体遵循被称为 ReAct 的模式(推理-行动-观察) 1. **推理** 分析文档和请求内容 2. **行动** 通过调用合适的工具执行操作 3. **观察** 工具执行结果 4. **重复** 上述步骤直到完全满足需求 这是使用 langGraph 实现的简单智能体实现。 ```python ## The graph builder = StateGraph(AgentState) # 定义节点:这些节点完成工作 builder.add_node("assistant", assistant) builder.add_node("tools", ToolNode(tools)) # 定义边:这些决定了控制流如何移动 builder.add_edge(START, "assistant") builder.add_conditional_edges( "assistant", # 如果最新消息需要工具,则路由至工具 # 否则,请直接回复 tools_condition, ) builder.add_edge("tools", "assistant") react_graph = builder.compile() # 展现管家的思考过程 display(Image(react_graph.get_graph(xray=True).draw_mermaid_png())) ``` ![ReAct Pattern](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/LangGraph/Agent.png) ## 管家实战示例 ### 示例1:简单计算 在以下示例中,我们添加这个 divide 示例仅作为演示用途。 ```python messages = [HumanMessage(content="Divide 6790 by 5")] messages = react_graph.invoke({"messages": messages, "input_file": None}) ``` 对话将会继续: ``` Human: Divide 6790 by 5 AI Tool Call: divide(a=6790, b=5) Tool Response: 1358.0 Alfred: The result of dividing 6790 by 5 is 1358.0. ``` ### 示例 2:分析 Wayne 大师的训练文档 当 Wayne 大师留下他的训练和​​用餐笔记时: ```python messages = [HumanMessage(content="According to the note provided by Mr. Wayne in the provided images. What's the list of items I should buy for the dinner menu?")] messages = react_graph.invoke({"messages": messages, "input_file": "Batman_training_and_meals.png"}) ``` 交互将进行: ``` 用户:根据 Wayne 先生在提供的图像中的注释。我应该为晚餐菜单购买哪些物品? AI Tool Call: extract_text(img_path="Batman_training_and_meals.png") Tool Response: [包含训练计划和菜单详情的提取文本] Alfred:根据晚餐菜单,您应该购买以下物品: 1. 草饲本地西冷牛排(Grass-fed local sirloin steak) 2. 有机菠菜(Organic spinach) 3. 皮克略辣椒(Piquillo peppers) 4. 土豆(用于烤制金黄香草土豆) 5. 鱼油(2 克) 确保牛排是草饲的,并且菠菜和辣椒是有机的,以获得最佳品质的餐点。 ``` ## 关键要点 若您希望创建自己的文档分析管家,请遵循以下关键原则: 1. **定义清晰的工具**(Define clear tools)用于特定文档相关任务 2. **创建强大的状态跟踪器**(Create a robust state tracker)以保持工具调用之间的上下文 3. **考虑错误处理机制**(Consider error handling)应对工具调用失败 5. **保持上下文感知能力**(Maintain contextual awareness)通过 add_messages 操作符确保历史交互的连贯性 遵循这些原则,您也能提供符合韦恩庄园标准的卓越文档分析服务。 *相信以上解释已足够详尽。恕我失陪,韦恩老爷的披风还需在夜巡前熨烫妥当。* ================================================ FILE: units/zh-CN/unit2/langgraph/first_graph.mdx ================================================ # 构建你的第一个 LangGraph 现在我们已经理解了基本构建模块,让我们通过构建第一个功能图来实践。我们将实现 Alfred 的邮件处理系统,他需要: 1. 阅读 incoming emails 2. 将其分类为 spam 或 legitimate 3. 为 legitimate 邮件起草初步响应 4. 当邮件合法时向 Mr. Wayne 发送信息(仅打印) 这个示例演示了如何使用 LangGraph 构建涉及基于 LLM 决策的工作流程结构。虽然这不能算是真正的 Agent(因为没有涉及工具),但本节更侧重于学习 LangGraph 框架而非 Agents。 > [!TIP] > 你可以在 这个 notebook 中查看完整代码,并通过 Google Colab 运行。 ## 工作流程 这是我们将要构建的工作流程: First LangGraph ## 环境设置 首先安装必要的包: ```python %pip install langgraph langchain_openai ``` 接下来,让我们导入必要的模块: ```python import os from typing import TypedDict, List, Dict, Any, Optional from langgraph.graph import StateGraph, END from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage, AIMessage ``` ## 步骤 1:定义我们的状态 让我们定义 Alfred 在电子邮件处理工作流程中需要跟踪哪些信息: ```python class EmailState(TypedDict): # 正在处理的电子邮件 email: Dict[str, Any] # 包含主题、发件人、正文等。 # 分析与决策 is_spam: Optional[bool] # 响应生成 draft_response: Optional[str] # 处理元数据 messages: List[Dict[str, Any]] # 跟踪与 LLM 的对话以进行分析 ``` > 💡 **提示:**让您的状态足够全面,以跟踪所有重要信息,但避免用不必要的细节使其变得臃肿。 ## 第 2 步:定义我们的节点 现在,让我们创建将形成我们节点的处理函数: ```python # Initialize our LLM model = ChatOpenAI(temperature=0) def read_email(state: EmailState): """Alfred reads and logs the incoming email""" email = state["email"] # 在这里我们可能会做一些初步的预处理 print(f"Alfred is processing an email from {email['sender']} with subject: {email['subject']}") # 这里不需要更改状态 return {} def classify_email(state: EmailState): """Alfred uses an LLM to determine if the email is spam or legitimate""" email = state["email"] # 为 LLM 准备提示 prompt = f""" As Alfred the butler, analyze this email and determine if it is spam or legitimate. Email: From: {email['sender']} Subject: {email['subject']} Body: {email['body']} First, determine if this email is spam. If it is spam, explain why. If it is legitimate, categorize it (inquiry, complaint, thank you, etc.). """ # Call the LLM messages = [HumanMessage(content=prompt)] response = model.invoke(messages) # 解析响应的简单逻辑(在实际应用中,您需要更强大的解析) response_text = response.content.lower() is_spam = "spam" in response_text and "not spam" not in response_text # 如果是垃圾邮件,请提取原因 spam_reason = None if is_spam and "reason:" in response_text: spam_reason = response_text.split("reason:")[1].strip() # 确定类别是否合法 email_category = None if not is_spam: categories = ["inquiry", "complaint", "thank you", "request", "information"] for category in categories: if category in response_text: email_category = category break # 更新消息以进行追踪 new_messages = state.get("messages", []) + [ {"role": "user", "content": prompt}, {"role": "assistant", "content": response.content} ] # 返回状态更新 return { "is_spam": is_spam, "spam_reason": spam_reason, "email_category": email_category, "messages": new_messages } def handle_spam(state: EmailState): """Alfred discards spam email with a note""" print(f"Alfred has marked the email as spam. Reason: {state['spam_reason']}") print("The email has been moved to the spam folder.") # 我们已处理完这封电子邮件 return {} def draft_response(state: EmailState): """Alfred drafts a preliminary response for legitimate emails""" email = state["email"] category = state["email_category"] or "general" # 为 LLM 准备提示词 prompt = f""" As Alfred the butler, draft a polite preliminary response to this email. Email: From: {email['sender']} Subject: {email['subject']} Body: {email['body']} This email has been categorized as: {category} Draft a brief, professional response that Mr. Hugg can review and personalize before sending. """ # Call the LLM messages = [HumanMessage(content=prompt)] response = model.invoke(messages) # 更新消息以进行追踪 new_messages = state.get("messages", []) + [ {"role": "user", "content": prompt}, {"role": "assistant", "content": response.content} ] # 返回状态更新 return { "draft_response": response.content, "messages": new_messages } def notify_mr_hugg(state: EmailState): """Alfred notifies Mr. Hugg about the email and presents the draft response""" email = state["email"] print("\n" + "="*50) print(f"Sir, you've received an email from {email['sender']}.") print(f"Subject: {email['subject']}") print(f"Category: {state['email_category']}") print("\nI've prepared a draft response for your review:") print("-"*50) print(state["draft_response"]) print("="*50 + "\n") # 我们已处理完这封电子邮件 return {} ``` ## 步骤 3:定义我们的路由逻辑 我们需要一个函数来确定分类后要采取哪条路径: ```python def route_email(state: EmailState) -> str: """Determine the next step based on spam classification""" if state["is_spam"]: return "spam" else: return "legitimate" ``` > 💡 **注意:** LangGraph 调用此路由函数来确定在分类节点之后要跟随哪条边。返回值必须与我们的条件边映射中的一个键匹配。 ## 步骤 4:创建 StateGraph 并定义边 现在我们将所有内容连接在一起: ```python # 创建 graph email_graph = StateGraph(EmailState) # 添加 nodes email_graph.add_node("read_email", read_email) email_graph.add_node("classify_email", classify_email) email_graph.add_node("handle_spam", handle_spam) email_graph.add_node("draft_response", draft_response) email_graph.add_node("notify_mr_hugg", notify_mr_hugg) # 添加 edges - 定义流程 email_graph.add_edge("read_email", "classify_email") # 从 classify_email 添加条件分支 email_graph.add_conditional_edges( "classify_email", route_email, { "spam": "handle_spam", "legitimate": "draft_response" } ) # 添加最后的 edges email_graph.add_edge("handle_spam", END) email_graph.add_edge("draft_response", "notify_mr_hugg") email_graph.add_edge("notify_mr_hugg", END) # 编译 graph compiled_graph = email_graph.compile() ``` 注意我们如何使用 LangGraph 提供的特殊“END”节点。这表示工作流完成的终端状态。 ## 步骤 5:运行应用程序 让我们用一封合法的电子邮件和一封垃圾邮件来测试我们的图表: ```python # 合法电子邮件示例 legitimate_email = { "sender": "john.smith@example.com", "subject": "Question about your services", "body": "Dear Mr. Hugg, I was referred to you by a colleague and I'm interested in learning more about your consulting services. Could we schedule a call next week? Best regards, John Smith" } # 垃圾邮件示例 spam_email = { "sender": "winner@lottery-intl.com", "subject": "YOU HAVE WON $5,000,000!!!", "body": "CONGRATULATIONS! You have been selected as the winner of our international lottery! To claim your $5,000,000 prize, please send us your bank details and a processing fee of $100." } # 处理合法电子邮件 print("\nProcessing legitimate email...") legitimate_result = compiled_graph.invoke({ "email": legitimate_email, "is_spam": None, "spam_reason": None, "email_category": None, "draft_response": None, "messages": [] }) # 处理垃圾邮件 print("\nProcessing spam email...") spam_result = compiled_graph.invoke({ "email": spam_email, "is_spam": None, "spam_reason": None, "email_category": None, "draft_response": None, "messages": [] }) ``` ## 第 6 步:使用 Langfuse 检查我们的邮件分类智能体 📡 随着 Alfred 对主分类智能体进行微调,他越来越厌倦调试其运行。智能体本质上是不可预测的,难以检查。但由于他的目标是构建终极垃圾邮件检测智能体并将其部署到生产中,因此他需要强大的可追溯性以供将来监控和分析。 为此,Alfred 可以使用可观察性工具(例如 [Langfuse](https://langfuse.com/))来跟踪和监控智能体。 首先,我们 pip install Langfuse: ```python %pip install -q langfuse ``` 接下来,我们将 Langfuse API 密钥和主机地址添加为环境变量。您可以通过注册 [Langfuse Cloud](https://cloud.langfuse.com) 或 [self-host Langfuse](https://langfuse.com/self-hosting) 获取 Langfuse 凭据。 ```python import os # Get keys for your project from the project settings page: https://cloud.langfuse.com os.environ["LANGFUSE_PUBLIC_KEY"] = "pk-lf-..." os.environ["LANGFUSE_SECRET_KEY"] = "sk-lf-..." os.environ["LANGFUSE_HOST"] = "https://cloud.langfuse.com" # 🇪🇺 EU region # os.environ["LANGFUSE_HOST"] = "https://us.cloud.langfuse.com" # 🇺🇸 US region ``` 然后,我们配置 [Langfuse `callback_handler`](https://langfuse.com/docs/integrations/langchain/tracing#add-langfuse-to-your-langchain-application),并通过将 `langfuse_callback` 添加到图的调用来检测智能体:`config={"callbacks": [langfuse_handler]}`。 ```python from langfuse.langchain import CallbackHandler # 为 LangGraph/Langchain 初始化 Langfuse CallbackHandler(跟踪) langfuse_handler = CallbackHandler() # 处理合法电子邮件 legitimate_result = compiled_graph.invoke( input={"email": legitimate_email, "is_spam": None, "spam_reason": None, "email_category": None, "draft_response": None, "messages": []}, config={"callbacks": [langfuse_handler]} ) ``` Alfred 现已连接 🔌!LangGraph 的运行记录在 Langfuse 中,使他能够全面了解智能体的行为。通过此设置,他可以重新查看之前的运行并进一步完善他的邮件分类智能体。 ![Langfuse 中的示例跟踪](https://langfuse.com/images/cookbook/huggingface-agent-course/langgraph-trace-legit.png) _[带有合法电子邮件的跟踪的公共链接](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/f5d6d72e-20af-4357-b232-af44c3728a7b?timestamp=2025-03-17T10%3A13%3A28.413Z&observation=6997ba69-043f-4f77-9445-700a033afba1)_ ## 可视化我们的图表 LangGraph 允许我们可视化我们的工作流程,以便更好地理解和调试其结构: ```python compiled_graph.get_graph().draw_mermaid_png() ``` Mail LangGraph 这会产生一个可视化表示,显示我们的节点如何连接以及可以采取的条件路径。 ## 我们构建了什么 我们创建了一个完整的电子邮件处理工作流程: 1. 接收传入的电子邮件 2. 使用 LLM 将其分类为垃圾邮件或合法邮件 3. 通过丢弃垃圾邮件来处理垃圾邮件 4. 对于合法电子邮件,起草回复并通知 Mr. Hugg 这展示了 LangGraph 使用 LLM 编排复杂工作流程同时保持清晰、结构化流程的强大功能。 ## 关键要点 - **状态管理**:我们定义了全面的状态来跟踪电子邮件处理的所有方面 - **节点实现**:我们创建了与 LLM 交互的功能节点 - **条件路由**:我们根据电子邮件分类实现了分支逻辑 - **终端状态**:我们使用 END 节点标记工作流程中的完成点 ## 下一步是什么? 在下一部分中,我们将探索 LangGraph 的更多高级功能,包括处理工作流中的人机交互以及根据多种条件实现更复杂的分支逻辑。 ================================================ FILE: units/zh-CN/unit2/langgraph/introduction.mdx ================================================ # 欢迎来到 `LangGraph` 的世界 Unit 2.3 缩略图 欢迎来到学习旅程的下一站!在本章节中,您将学习如何使用 [`LangGraph`](https://github.com/langchain-ai/langgraph) 框架来构建应用程序,该框架能帮助您组织和编排复杂的 LLM 工作流。 `LangGraph` 是一个通过提供对智能体流程的**控制**工具,帮助您构建**生产就绪**应用程序的框架。 ## 模块概览 在本单元中,您将探索: ### 1️⃣ [什么是 LangGraph?何时使用它?](./when_to_use_langgraph) ### 2️⃣ [LangGraph 的构建模块](./building_blocks) ### 3️⃣ [邮件分拣管家 Alfred](./first_graph) ### 4️⃣ [文档分析智能体 Alfred](./document_analysis_agent) ### 5️⃣ [随堂测验](./quizz1) > [!WARNING] > 本节示例需要访问强大的 LLM/VLM 模型。我们使用 GPT-4o API 运行这些示例,因为该模型与 LangGraph 具有最佳兼容性。 通过本单元的学习,您将掌握构建健壮、有序且生产就绪的应用程序的能力! 需要说明的是,本节只是 LangGraph 的入门介绍,更多高级主题可以通过 LangChain 学院的免费课程学习:[LangGraph 入门指南](https://academy.langchain.com/courses/intro-to-langgraph) 让我们即刻启程! ## 扩展资源 - [LangGraph 智能体](https://langchain-ai.github.io/langgraph/) - LangGraph 智能体示例 - [LangChain 学院](https://academy.langchain.com/courses/intro-to-langgraph) - 来自 LangChain 的完整 LangGraph 课程 ================================================ FILE: units/zh-CN/unit2/langgraph/quiz1.mdx ================================================ # 测试你对 LangGraph 的理解 让我们通过快速测验来测试你对 `LangGraph` 的理解!这将帮助你巩固目前学到的关键概念。 本测验为可选项目,不计入评分。 ### Q1: LangGraph 的主要目的是什么? 哪个描述最能体现 LangGraph 的设计目标? --- ### Q2: 在"控制 vs 自由"的权衡中,LangGraph 的定位是什么? 哪个陈述最能体现 LangGraph 在 agent 设计中的方法? --- ### Q3: State 在 LangGraph 中扮演什么角色? 选择对 LangGraph 中 State 最准确的描述。 ### Q4: LangGraph 中的条件边(Conditional Edge)是什么? 选择最准确的描述。 --- ### Q5: LangGraph 如何帮助解决 LLM 的幻觉问题? 选择最佳答案。 恭喜完成测验!🎉 如果有答错的问题,建议回顾前文内容加强理解。接下来我们将探索 LangGraph 的更高级功能,学习如何构建更复杂的 agent 工作流。 ================================================ FILE: units/zh-CN/unit2/langgraph/when_to_use_langgraph.mdx ================================================ # 什么是 `LangGraph`? `LangGraph` 是由 [LangChain](https://www.langchain.com/) 开发的框架,**用于管理集成 LLM 的应用程序的控制流**。 ## `LangGraph` 和 `LangChain` 有何不同? LangChain 提供了与模型和其他组件交互的标准接口,可用于检索、LLM 调用和工具调用。 LangChain 的类可能会在 LangGraph 中使用,但不是必须的。 这两个包是独立的可以单独使用,但最终你在网上找到的资源都会同时使用这两个包。 ## 何时应该使用 `LangGraph`? ### 控制 vs 自由度 在设计 AI 应用时,你面临 **控制** 与 **自由度** 的基本权衡: - **自由度** 赋予 LLM 更多创造性地解决问题的空间 - **控制** 能确保可预测的行为并维持安全护栏 像 *smolagents* 中的代码智能体(Code Agents)具有高度自由度。它们可以在单个行动步骤中调用多个工具、创建自己的工具等。然而,这种行为会使它们比使用 JSON 的常规 Agent 更难预测和控制! `LangGraph` 则位于光谱的另一端,当你需要对智能体的执行进行 **"控制"** 时,它就会大放异彩。 当你需要 **对应用程序保持控制** 时,LangGraph 特别有价值。它为你提供了构建可预测流程应用程序的工具,同时仍能利用 LLM 的强大能力。 简而言之,如果你的应用程序包含需要以特定方式编排的多个步骤,并在每个连接点做出决策,**LangGraph 就能提供你所需的结构**。 举个例子,假设我们要构建一个能够回答文档相关问题的 LLM 助手。 由于 LLM 最擅长理解文本,在回答问题之前,你需要将其他复杂模态(图表、表格)转换为文本。但这个选择取决于你拥有的文档类型! 我选择将这种分支流程表示为: 控制流程图 > 💡 **提示:** 左侧部分不是智能体,因为这里不涉及工具调用。但右侧部分需要编写代码来查询 xls 文件(转换为 pandas 并操作它)。 虽然这个分支是确定性的,但你也可以设计基于 LLM 输出结果的非确定性条件分支。 LangGraph 表现出色的关键场景包括: - 需要显式控制流程的 **多步骤推理过程** - 需要在步骤之间 **保持状态持久化** 的应用程序 - **结合确定性逻辑与 AI 能力** 的系统 - 需要 **人工介入** 的工作流 - 多个组件协同工作的 **复杂智能体架构** 本质上,只要有可能,**作为人类** 就应该根据每个操作的输出设计行动流程,并据此决定下一步执行什么。在这种情况下,LangGraph 就是你正确的选择! 在我看来,`LangGraph` 是市场上最适合生产环境的智能体框架。 ## LangGraph 如何工作? 其核心在于,`LangGraph` 使用有向图结构来定义应用程序的流程: - **节点** 表示独立的处理步骤(如调用 LLM、使用工具或做出决策) - **边** 定义步骤之间可能的转换 - **状态** 由用户定义和维护,并在执行期间在节点间传递。当决定下一个目标节点时,我们查看的就是当前状态 我们将在下一章更深入地探讨这些基本模块! ## 它和普通 Python 有何不同?为什么需要 LangGraph? 你可能会想:"我可以用常规 Python 代码和 if-else 语句来处理所有这些流程,对吧?" 虽然技术上可行,但对于构建复杂系统,LangGraph 相比原生 Python 有 **诸多优势**。没有 LangGraph 你也能构建相同应用,但它能为你提供更便捷的工具和抽象。 它包含状态管理、可视化、日志追踪(traces)、内置的人类介入机制等功能。 ================================================ FILE: units/zh-CN/unit2/llama-index/README.md ================================================ # 目录 此 LlamaIndex 框架大纲是课程第 2 单元的一部分。您可以在 hf.co/learn 上访问有关 LlamaIndex 的第 2 单元 👉 这里 | 标题 | 描述 | | -------------------------------- | ------------------------------------------------------------------------------------ | | [介绍](introduction.mdx) | LlamaIndex 简介 | | [LlamaHub](llama-hub.mdx) | LlamaHub:集成、智能体和工具注册表 | | [组件](components.mdx) | 组件:工作流的构件 | | [工具](tools.mdx) | 工具:如何在 LlamaIndex 中构建工具 | | [测验 1](quiz1.mdx) | 测验 1 | | [智能体](agents.mdx) | 智能体:如何在 LlamaIndex 中建立智能体 | | [工作流](workflows.mdx) | 工作流:由按顺序执行的组件组成的一系列步骤和事件 | | [测验 2](quiz2.mdx) | 测验 2 | | [结论](conclusion.mdx) | 结论 | ================================================ FILE: units/zh-CN/unit2/llama-index/agents.mdx ================================================ # 在 LlamaIndex 中使用智能体 还记得我们之前那位得力的管家智能体 Alfred 吗?现在他要迎来重大升级了! 在了解了 LlamaIndex 中的工具后,我们可以赋予 Alfred 新的能力来更好地服务我们。 不过在继续之前,让我们先回顾一下智能体(如 Alfred)的核心机制。 在第一单元中我们学习到: > 智能体是一个利用 AI 模型与环境交互以实现用户定义目标的系统。它通过结合推理、规划和动作执行(通常通过外部工具)来完成各种任务。 LlamaIndex 支持**三种主要类型的推理智能体**: ![智能体类型](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/agents.png) 1. `函数调用智能体` - 适用于支持调用特定函数的 AI 模型 2. `ReAct 智能体` - 适用于具有聊天或文本完成能力的 AI 模型,擅长处理复杂推理任务 3. `高级自定义智能体` - 使用更复杂的方法处理高阶任务和工作流 > [!TIP] > 有关高级智能体的更多信息,请访问 BaseWorkflowAgent ## 初始化智能体 > [!TIP] > 您可以通过 这个 Notebook 跟随代码实践(使用 Google Colab 运行)。 创建智能体时,我们首先需要为其提供**定义其能力的功能/工具集合**。 让我们看看如何使用基础工具创建智能体。当前实现中,智能体会自动使用函数调用 API(如果可用),或标准的 ReAct 智能体循环。 支持工具/函数 API 的 LLM 是相对较新的技术,它们通过避免特定提示工程、允许 LLM 根据提供的模式创建工具调用,提供了强大的工具调用能力。 ReAct 智能体同样擅长复杂推理任务,可与任何具备聊天或文本完成能力的 LLM 配合使用。这类智能体的响应更详细,会展示其决策背后的推理过程。 ```python from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI from llama_index.core.agent.workflow import AgentWorkflow from llama_index.core.tools import FunctionTool # 定义示例工具--类型注释、函数名和 docstrings 都包含在解析的模式中! def multiply(a: int, b: int) -> int: """Multiplies two integers and returns the resulting integer""" return a * b # 初始化 llm llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") # 初始化 agent agent = AgentWorkflow.from_tools_or_functions( [FunctionTool.from_defaults(multiply)], llm=llm ) ``` **智能体默认是无状态的**,如需记忆过往交互,需显式使用 `Context` 对象。 这在需要记忆历史交互的场景中非常有用,例如:需要跨消息保持上下文的聊天机器人,或需要追踪长期任务进度的任务管理器。 ```python # stateless response = await agent.run("What is 2 times 2?") # remembering state from llama_index.core.workflow import Context ctx = Context(agent) response = await agent.run("My name is Bob.", ctx=ctx) response = await agent.run("What was my name again?", ctx=ctx) ``` 您会注意到 `LlamaIndex` 中的智能体采用异步模式(使用 Python 的 `await` 操作符)。如果您是 Python 异步编程的新手,或需要复习相关知识,请参考 [官方异步编程指南](https://docs.llamaindex.ai/en/stable/getting_started/async_python/)。 现在我们已经掌握基础知识,接下来让我们探索如何为智能体赋予更复杂的工具能力。 ## 使用 QueryEngineTools 创建 RAG 智能体 **智能体增强检索(Agentic RAG)** 是通过智能体实现数据问答的强大范式。我们可以为 Alfred 配备多种工具来辅助问题解答。 但不同于传统 RAG 直接基于文档回答问题,Alfred 能够自主决定是否使用其他工具或流程来响应查询。 ![智能体增强 RAG](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/agentic-rag.png) 将 `QueryEngine` 封装为智能体工具非常简单。 在此过程中,我们需要**定义工具名称和描述**,这些元数据将帮助 LLM 正确选择和使用工具。 以下示例演示如何基于[组件章节](02_components)创建的 `QueryEngine` 加载 `QueryEngineTool`: ```python from llama_index.core.tools import QueryEngineTool query_engine = index.as_query_engine(llm=llm, similarity_top_k=3) # as shown in the previous section query_engine_tool = QueryEngineTool.from_defaults( query_engine=query_engine, name="name", description="a specific description", return_direct=False, ) query_engine_agent = AgentWorkflow.from_tools_or_functions( [query_engine_tool], llm=llm, system_prompt="You are a helpful assistant that has access to a database containing persona descriptions. " ) ``` ## 创建多智能体系统 `AgentWorkflow` 类原生支持多智能体系统。通过为每个智能体分配名称和描述,系统可维护单一活跃会话主体,同时允许智能体之间进行任务交接。 通过精准定义每个智能体的职责边界,我们能够有效提升系统响应消息时的整体准确性。 **LlamaIndex 中的智能体也可直接作为其他智能体的工具**,这种设计支持构建复杂的定制化场景: ```python from llama_index.core.agent.workflow import ( AgentWorkflow, FunctionAgent, ReActAgent, ) # Define some tools def add(a: int, b: int) -> int: """Add two numbers.""" return a + b def subtract(a: int, b: int) -> int: """Subtract two numbers.""" return a - b # 创建智能体配置 # 注意:我们可以在此使用 FunctionAgent 或 ReActAgent。 # FunctionAgent 适用于具有函数调用 API 的 LLM。 # ReActAgent 适用于任何 LLM。 calculator_agent = ReActAgent( name="calculator", description="Performs basic arithmetic operations", system_prompt="You are a calculator assistant. Use your tools for any math operation.", tools=[add, subtract], llm=llm, ) query_agent = ReActAgent( name="info_lookup", description="Looks up information about XYZ", system_prompt="Use your tool to query a RAG system to answer information about XYZ", tools=[query_engine_tool], llm=llm ) # 创建并运行工作流程 agent = AgentWorkflow( agents=[calculator_agent, query_agent], root_agent="calculator" ) # 运行系统 response = await agent.run(user_msg="Can you add 5 and 3?") ``` > [!TIP] > 还没学够吗?在《AgentWorkflow 基本介绍》《Agent 学习指南》中,您可以了解到更多关于流媒体、上下文序列化和人在环路中的信息! 现在我们已经掌握了 LlamaIndex 中智能体和工具的基础知识,接下来让我们探索如何利用 LlamaIndex 来**创建可配置、易管理的工作流**! ================================================ FILE: units/zh-CN/unit2/llama-index/components.mdx ================================================ # LlamaIndex 中的组件是什么? 还记得第一单元中我们那位得力的管家智能体 Alfred 吗? 要有效协助我们,Alfred 需要理解我们的请求,并**准备、查找和使用相关信息来帮助完成任务**。 这正是 LlamaIndex 组件发挥作用的地方。 虽然 LlamaIndex 包含众多组件,但**我们将重点关注 `QueryEngine` 组件**。 为什么?因为它可以作为智能体的检索增强生成(RAG)工具。 那么什么是 RAG?大语言模型通过海量数据训练获得通用知识, 但它们可能缺乏相关且最新的特定领域数据。 RAG 通过从您的数据中检索相关信息并传递给 LLM 来解决这个问题。 ![RAG](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/rag.png) 试想 Alfred 的工作机制: 1. 您让 Alfred 帮忙策划晚宴 2. Alfred 需要查看您的日历、饮食偏好和过往成功菜单 3. `QueryEngine` 帮助 Alfred 查找这些信息并用于晚宴策划 这使得 `QueryEngine` 成为在 LlamaIndex 中**构建智能 RAG 工作流的核心组件**。 正如 Alfred 需要检索家庭信息才能发挥作用,任何智能体都需要理解和查找相关数据的能力。 `QueryEngine` 正好提供了这种核心能力。 现在让我们深入探讨如何**组合组件来创建 RAG 流程**。 ## 使用组件构建 RAG 流程 > [!TIP] > 您可以通过 这个 Notebook 跟随代码实践(使用 Google Colab 运行)。 RAG 包含五个关键阶段,这些阶段将构成您构建的大部分应用: 1. **加载**:将数据从原始位置(文本文件、PDF、网站、数据库或 API)导入工作流。LlamaHub 提供数百种集成方案 2. **索引**:创建便于查询的数据结构。对于 LLM 通常意味着创建向量嵌入——数据的语义数值表示,也可以包含其他元数据策略 3. **存储**:索引完成后需要持久化存储,避免重复构建 4. **查询**:支持多种检索策略,包括子查询、多步查询和混合策略 5. **评估**:通过客观指标评估响应准确性、忠实度和响应速度,对比不同策略效果 接下来我们将演示如何使用组件实现这些阶段。 ### 数据加载与嵌入 如前所述,LlamaIndex 可以基于您的自有数据进行操作,但**在访问数据之前,我们需要先完成加载**。 LlamaIndex 提供三种主要的数据加载方式: 1. `SimpleDirectoryReader`: 内置加载器,支持从本地目录加载多种文件类型 2. `LlamaParse`: LlamaIndex 官方 PDF 解析工具,提供托管 API 服务 3. `LlamaHub`: 包含数百个数据加载库的注册中心,支持从任意数据源获取数据 > [!TIP] > 对于复杂数据源,建议深入了解 LlamaHub 加载器和 LlamaParse 解析器的使用方法。 **最简单的数据加载方式是使用 `SimpleDirectoryReader`**。 这个多功能组件可以从文件夹中加载各类文件,并将其转换为 LlamaIndex 可处理的 `Document` 对象。 以下是具体使用方法: ```python from llama_index.core import SimpleDirectoryReader reader = SimpleDirectoryReader(input_dir="path/to/directory") documents = reader.load_data() ``` 加载文档后,我们需要将其分解为更小的单元——`Node`对象。 `Node`是原始文档中的文本片段,既便于AI处理,又保留了对原`Document`对象的引用。 `IngestionPipeline`通过两个关键转换步骤帮助我们创建这些节点: 1. `SentenceSplitter`通过自然语句边界将文档拆分为可管理的文本块 2. `HuggingFaceInferenceAPIEmbedding`将每个文本块转换为数值化的向量表示——这种以AI能高效处理的方式捕捉语义信息 该流程能帮助我们以更适合搜索和分析的方式组织文档。 ```python from llama_index.core import Document from llama_index.embeddings.huggingface_api import HuggingFaceInferenceAPIEmbedding from llama_index.core.node_parser import SentenceSplitter from llama_index.core.ingestion import IngestionPipeline # 通过转换创建管道 pipeline = IngestionPipeline( transformations=[ SentenceSplitter(chunk_overlap=0), HuggingFaceInferenceAPIEmbedding(model_name="BAAI/bge-small-en-v1.5"), ] ) nodes = await pipeline.arun(documents=[Document.example()]) ``` ### 存储与索引文档 创建完`节点`对象后,我们需要对其进行索引,使其可以被搜索,但在此之前,我们需要一个存储数据的地方。 由于我们使用的是摄取管道,因此可以直接在管道上附加一个向量存储来填充数据。 在本例中,我们将使用 `Chroma` 来存储我们的文档。
安装 ChromaDB 正如在[关于 LlamaHub 的章节](llama-hub)中所介绍的,我们可以使用以下命令安装 ChromaDB 向量存储: ```bash pip install llama-index-vector-stores-chroma ```
```python import chromadb from llama_index.vector_stores.chroma import ChromaVectorStore db = chromadb.PersistentClient(path="./alfred_chroma_db") chroma_collection = db.get_or_create_collection("alfred") vector_store = ChromaVectorStore(chroma_collection=chroma_collection) pipeline = IngestionPipeline( transformations=[ SentenceSplitter(chunk_size=25, chunk_overlap=0), HuggingFaceInferenceAPIEmbedding(model_name="BAAI/bge-small-en-v1.5"), ], vector_store=vector_store, ) ``` > [!TIP] > An overview of the different vector stores can be found in the LlamaIndex documentation. 这就是向量嵌入的作用所在--通过将查询和节点嵌入同一向量空间,我们可以找到相关的匹配项。 `向量存储索引`会为我们处理这个问题,使用我们在摄取时使用的相同嵌入模型来确保一致性。 让我们看看如何从向量存储和嵌入中创建该索引: ```python from llama_index.core import VectorStoreIndex from llama_index.embeddings.huggingface_api import HuggingFaceInferenceAPIEmbedding embed_model = HuggingFaceInferenceAPIEmbedding(model_name="BAAI/bge-small-en-v1.5") index = VectorStoreIndex.from_vector_store(vector_store, embed_model=embed_model) ``` 所有信息都会自动保存在 `ChromaVectorStore` 对象和传递的目录路径中。 太棒了 现在我们可以轻松保存和加载索引了,让我们探索一下如何以不同方式查询索引。 ### 使用提示词和 LLM 查询 VectorStoreIndex 在查询索引之前,我们需要将其转换为查询接口。最常见的转换选项包括: - `as_retriever`:用于基础文档检索,返回带有相似度得分的`NodeWithScore`对象列表 - `as_query_engine`:用于单次问答交互,返回书面响应 - `as_chat_engine`:用于需要保持跨消息记忆的对话交互,通过聊天历史记录和索引上下文返回书面响应 我们将重点介绍查询引擎(query engine),因为它在类智能体交互中更为常见。 我们还需要向查询引擎传入一个大语言模型(LLM)用于生成响应。 ```python from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") query_engine = index.as_query_engine( llm=llm, response_mode="tree_summarize", ) query_engine.query("What is the meaning of life?") # The meaning of life is 42 ``` ### 响应处理 底层实现中,查询引擎不仅使用 LLM 来回答问题,还会采用 `ResponseSynthesizer` 作为响应处理策略。 同样,该组件完全可定制,但默认提供三种高效的工作策略: - `refine`(迭代优化): 通过逐个处理每个检索到的文本块来创建并优化答案。每个 Node/文本块都会触发独立的 LLM 调用 - `compact`(紧凑模式,默认): 与迭代优化类似,但会预先拼接文本块,从而减少 LLM 调用次数 - `tree_summarize`(树状归纳): 通过遍历所有检索到的文本块并构建答案的树状结构来生成详细响应 > [!TIP] > 通过底层组合 API 实现查询流程的精细控制。该 API 允许您自定义和优化查询流程的每个步骤,与 Workflows 配合使用效果更佳 由于语言模型的输出具有不可预测性,我们需要**通过评估答案质量**来确保结果的可靠性。 ### 评估与可观测性 LlamaIndex 提供**内置评估工具来量化响应质量**。 这些评估器利用 LLM 对回答进行多维度分析。 主要评估器包括: - `FaithfulnessEvaluator`(忠实性评估器): 验证答案是否得到上下文的支持 - `AnswerRelevancyEvaluator`(答案相关性评估器): 评估答案与问题的关联程度 - `CorrectnessEvaluator`(正确性评估器): 检验答案的正确性 ```python from llama_index.core.evaluation import FaithfulnessEvaluator query_engine = # from the previous section llm = # from the previous section # 查询索引 evaluator = FaithfulnessEvaluator(llm=llm) response = query_engine.query( "What battles took place in New York City in the American Revolution?" ) eval_result = evaluator.evaluate_response(response=response) eval_result.passing ``` 即使没有直接评估,我们也可以**通过可观察性深入了解我们的系统是如何运行的。** 当我们构建更复杂的工作流程并想要了解每个组件是如何运行的时候,这尤其有用。
安装 LlamaTrace 正如 [LlamaHub 部分](llama-hub) 中介绍的那样,我们可以使用以下命令从 Arize Phoenix 安装 LlamaTrace 回调: ```bash pip install -U llama-index-callbacks-arize-phoenix ``` 此外,我们需要将 `PHOENIX_API_KEY` 环境变量设置为我们的 LlamaTrace API 密钥。我们可以通过以下方式获取此密钥: - 在 [LlamaTrace](https://llamatrace.com/login) 创建一个帐户 - 在您的帐户设置中生成 API 密钥 - 使用下面代码中的 API 密钥启用跟踪
```python import llama_index import os PHOENIX_API_KEY = "" os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = f"api_key={PHOENIX_API_KEY}" llama_index.core.set_global_handler( "arize_phoenix", endpoint="https://llamatrace.com/v1/traces" ) ``` > [!TIP] > 想要了解有关组件的更多信息以及如何使用它们?继续您的旅程,阅读组件指南RAG 指南。 我们已经了解了如何使用组件创建 `QueryEngine`。现在,让我们看看如何**将 `QueryEngine` 用作智能体的工具!** ================================================ FILE: units/zh-CN/unit2/llama-index/conclusion.mdx ================================================ # 结语 恭喜完成第二单元 `llama-index` 模块的学习 🥳 您已掌握 `llama-index` 的核心基础,并学会了如何构建自主式工作流! 现在凭借掌握的 `llama-index` 技能,您可以开始创建解决实际任务的搜索引擎。 在本单元的下个模块中,您将学习**如何用 LangGraph 构建智能体**。 最后,我们诚挚希望**听取您对课程的评价和改进建议**。 如有任何反馈,请👉[填写此表单](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ### 持续学习,保持热情 🤗 ================================================ FILE: units/zh-CN/unit2/llama-index/introduction.mdx ================================================ # LlamaIndex 简介 欢迎来到本模块,您将学习如何使用 [LlamaIndex](https://www.llamaindex.ai/) 工具包构建基于大语言模型(LLM)的智能体。 LlamaIndex 是**通过索引和工作流在您的数据上创建 LLM 驱动智能体的完整工具包**。本课程我们将重点关注构建 LlamaIndex 智能体的三个核心部分:**组件**、**智能体与工具**以及**工作流**。 ![LlamaIndex](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/thumbnail.png) 让我们解析这些核心要素及其对智能体的支持: - **组件**是 LlamaIndex 中的基础构建模块,包括提示词、模型和数据库等。组件通常帮助 LlamaIndex 与其他工具和库进行集成。 - **工具**:提供特定功能的组件,如搜索、计算或访问外部服务。它们是支撑智能体执行任务的基础模块。 - **智能体**:能够自主使用工具并做出决策的独立组件,通过协调工具使用来实现复杂目标。 - **工作流**:按步骤处理逻辑的流程。智能体工作流是一种无需显式使用智能体即可构建智能行为的方式。 ## LlamaIndex 的独特之处 虽然LlamaIndex与其他框架(如 smolagents)有相似之处,但具备以下关键优势: - **清晰的工作流系统**。通过事件驱动和异步优先的语法,工作流帮助您逐步分解智能体的决策过程,实现逻辑的清晰组合与组织。 - **基于 LlamaParse 的高级文档解析** 专为 LlamaIndex 打造的文档解析工具,尽管是付费功能,但提供无缝集成体验。 - **丰富的即用组件** 凭借长期的技术积累,LlamaIndex 与众多框架兼容,提供大量经过验证的可靠组件(如 LLM、检索器、索引等)。 - **LlamaHub** 提供了数百个此类组件、智能体和工具的注册中心,方便您在 LlamaIndex 中直接使用。 这些概念在不同场景中都是创建实用智能体的必要元素。 后续章节我们将深入解析每个概念。 掌握这些知识后,我们将运用所学**通过 Alfred 智能体创建实际应用案例**! 准备好探索 LlamaIndex 的精彩世界了吗?让我们立即启程,**通过 LlamaHub 查找并安装所需集成吧!🚀** ================================================ FILE: units/zh-CN/unit2/llama-index/llama-hub.mdx ================================================ # LlamaHub 简介 **LlamaHub 是一个包含数百个集成组件、智能体和工具的注册中心,这些资源均可用于LlamaIndex框架。** ![LlamaHub](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/llama-hub.png) 在本课程中我们将使用多种集成组件,因此让我们首先了解LlamaHub及其如何助力开发。 接下来我们将学习如何查找和安装所需组件的依赖项。 ## 安装 LlamaIndex的安装说明可通过结构清晰的**[LlamaHub官网](https://llamahub.ai/)**获取。 初次接触可能会感到有些复杂,但大多数**安装命令都遵循易于记忆的格式**: ```bash pip install llama-index-{component-type}-{framework-name} ``` 让我们尝试使用 [Hugging Face 推理 API 集成](https://llamahub.ai/l/llms/llama-index-llms-huggingface-api?from=llms) 安装 LLM 组件的依赖项。 ```bash pip install llama-index-llms-huggingface-api ``` ## 用法 安装后,我们可以看到使用模式。您会注意到导入路径跟在安装命令后面! 下面,我们可以看到**LLM 组件的 Hugging Face 推理 API** 的使用示例。 ```python from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI llm = HuggingFaceInferenceAPI( model_name="Qwen/Qwen2.5-Coder-32B-Instruct", temperature=0.7, max_tokens=100, token="hf_xxx", ) llm.complete("Hello, how are you?") # I am good, how can I help you today? ``` 太棒了,我们现在知道如何查找、安装和使用我们所需组件的集成。 **让我们深入了解这些组件**,看看如何使用它们来构建我们自己的智能体。 ================================================ FILE: units/zh-CN/unit2/llama-index/quiz1.mdx ================================================ # 小测验(不计分) [[quiz1]] 到目前为止,我们已经讨论了 LlamaIndex 的关键组件和工具。 是时候做个小测验了,因为**自我测试**是最好的学习方式,也能[避免能力错觉](https://www.coursera.org/lecture/learning-how-to-learn/illusions-of-competence-BuFzf)。 这将帮助您发现**哪些知识需要加强**。 本测验为可选项目,不计入成绩。 ### Q1: 什么是 QueryEngine? 以下哪项最能描述 QueryEngine 组件? --- ### Q2: FunctionTools 的作用是什么? 为什么 FunctionTools 对 Agent 很重要? --- ### Q3: LlamaIndex 中的 Toolspecs 是什么? Toolspecs 的主要目的是什么? --- ### Q4: 创建工具时需要什么? 创建工具时必须包含哪些信息? --- 恭喜完成测验 🥳!如果有错误,请重新阅读章节巩固知识。如果全部正确,您已准备好深入学习这些组件的构建了! ================================================ FILE: units/zh-CN/unit2/llama-index/quiz2.mdx ================================================ # 快速自测(不计分)[[quiz2]] 什么?!又是测验?我们知道,我们知道...😅但这个简短的不计分测验是为了**帮助您巩固刚学到的关键概念**。 本测验涵盖智能体工作流程和交互——这些是构建高效AI智能体的核心组件。 ### Q1: AgentWorkflow 在 LlamaIndex 中的主要作用是什么? --- ### Q2: 哪个对象用于跟踪工作流的状态? --- ### Q3: 如果希望智能体记住之前的交互,应该使用哪个方法? --- ### Q4: Agentic RAG 的关键特性是什么? --- 明白了吗?太棒了!现在让我们**简要回顾一下本单元!** ================================================ FILE: units/zh-CN/unit2/llama-index/tools.mdx ================================================ # 在 LlamaIndex 中使用工具 **定义清晰明确的工具集对性能至关重要。** 正如我们在[第一单元](../../unit1/tools)中讨论的,清晰的工具接口更便于 LLM 使用。 就像人类工程师使用的软件API接口一样,如果工具的工作原理容易理解,LLM就能更好地利用它。 LlamaIndex 中主要包含**四种工具类型**: ![工具](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/tools.png) 1. `FunctionTool`:将任意 Python 函数转换为智能体可以使用的工具。它能自动识别函数的工作原理。 2. `QueryEngineTool`:让智能体能够使用查询引擎的工具。由于智能体本身基于查询引擎构建,因此它们也可以将其他智能体作为工具使用。 3. `Toolspecs`:由社区创建的预设工具集,通常包含针对特定服务(如 Gmail)的工具。 4. `Utility Tools`:帮助处理来自其他工具的大量数据的特殊工具。 下面我们将详细讲解每种工具的使用方法。 ## 创建FunctionTool > [!TIP] > 您可以通过这个 Notebook中的代码进行实践(支持 Google Colab 运行)。 FunctionTool 提供了一种简单的方式,可以将任意 Python 函数封装成智能体可用的工具。 你可以传递同步或异步函数给这个工具,并可选地指定`name`和`description`参数。 工具名称和描述尤为重要,它们能帮助智能体理解何时以及如何有效地使用该工具。 以下示例演示了如何创建并调用 FunctionTool。 ```python from llama_index.core.tools import FunctionTool def get_weather(location: str) -> str: """Useful for getting the weather for a given location.""" print(f"Getting weather for {location}") return f"The weather in {location} is sunny" tool = FunctionTool.from_defaults( get_weather, name="my_weather_tool", description="Useful for getting the weather for a given location.", ) tool.call("New York") ``` > [!TIP] > 使用带有函数调用的智能体或 LLM 时,所选工具(以及为该工具编写的参数)在很大程度上取决于工具名称以及工具用途和参数的描述。在函数调用指南。 ## 创建 QueryEngineTool 我们在上一单元中定义的 `QueryEngine` 可以使用 `QueryEngineTool` 类轻松转换为工具。 让我们看看如何在下面的示例中从 `QueryEngine` 创建 `QueryEngineTool`。 ```python from llama_index.core import VectorStoreIndex from llama_index.core.tools import QueryEngineTool from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI from llama_index.embeddings.huggingface_api import HuggingFaceInferenceAPIEmbedding from llama_index.vector_stores.chroma import ChromaVectorStore embed_model = HuggingFaceInferenceAPIEmbedding("BAAI/bge-small-en-v1.5") db = chromadb.PersistentClient(path="./alfred_chroma_db") chroma_collection = db.get_or_create_collection("alfred") vector_store = ChromaVectorStore(chroma_collection=chroma_collection) index = VectorStoreIndex.from_vector_store(vector_store, embed_model=embed_model) llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") query_engine = index.as_query_engine(llm=llm) tool = QueryEngineTool.from_defaults(query_engine, name="some useful name", description="some useful description") ``` ## 创建 Toolspecs 将 `ToolSpecs` 视为可以和谐协作的工具集合 - 就像一个组织良好的专业工具包。 就像机械师的工具包包含用于车辆维修的互补工具一样,`ToolSpec` 会将相关工具组合起来用于特定目的。 例如,会计智能体的 `ToolSpec` 可以优雅地集成电子表格功能、电子邮件功能和计算工具,以精确高效地处理财务任务。
安装 Google Toolspec 正如 [LlamaHub 部分](llama-hub) 中介绍的那样,我们可以使用以下命令安装 Google toolspec: ```python pip install llama-index-tools-google ```
现在我们可以加载工具规范并将其转换为工具列表。 ```python from llama_index.tools.google import GmailToolSpec tool_spec = GmailToolSpec() tool_spec_list = tool_spec.to_tool_list() ``` 为了更详细地了解这些工具,我们可以查看每个工具的`元数据`。 ```python [(tool.metadata.name, tool.metadata.description) for tool in tool_spec_list] ``` ## 实用工具 很多时候,直接查询 API **可能会返回过量数据**,其中部分可能无关紧要、超出 LLM 的上下文窗口容量,或导致不必要的 token 消耗。 让我们详细了解以下两个主要实用工具: 1. `OnDemandToolLoader`:该工具可将任何现有的 LlamaIndex 数据加载器(BaseReader 类)转化为智能体可使用的工具。该工具可通过调用数据加载器`load_data`所需的所有参数以及自然语言查询字符串来触发。在执行过程中,我们首先从数据加载器加载数据,建立索引(例如使用向量存储),然后进行"按需"查询。这三个步骤都在单个工具调用中完成。 2. `LoadAndSearchToolSpec`:该工具规范接受任何现有工具作为输入。作为工具规范,它实现了`to_tool_list`方法,调用该方法时会返回两个工具:加载工具和搜索工具。加载工具的执行会调用底层工具并对输出建立索引(默认使用向量索引)。搜索工具的执行会接受查询字符串作为输入并调用底层索引。 > [!TIP] > 您可以在LlamaHub找到各种工具规范和实用工具 现在我们已经理解了 LlamaIndex 中智能体和工具的基础知识,接下来让我们看看如何**使用 LlamaIndex 创建可配置且易管理的工作流程!** ================================================ FILE: units/zh-CN/unit2/llama-index/workflows.mdx ================================================ # 在 LlamaIndex 中创建智能工作流 LlamaIndex 中的工作流提供了一种结构化方式来将代码组织成可管理的顺序步骤。 这种工作流通过定义由`事件(Events)`触发的`步骤(Steps)`来创建,这些步骤本身也会发出`事件`来触发后续步骤。 让我们看看 Alfred 展示的用于 RAG 任务的 LlamaIndex 工作流。 ![工作流示意图](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/workflows.png) **工作流具有以下关键优势:** - 将代码清晰地组织为离散步骤 - 事件驱动架构实现灵活控制流 - 步骤间类型安全的通信 - 内置状态管理 - 支持简单和复杂的智能体交互 正如您可能猜到的,**工作流在保持对整体流程控制的同时,实现了智能体的自主性之间的完美平衡。** 现在让我们学习如何自己创建工作流! ## 创建工作流 > [!TIP] > 您可以通过 这个笔记本 中的代码进行实践,可使用 Google Colab 运行。 ### 基础工作流创建
安装工作流包 如 [LlamaHub 章节](llama-hub) 介绍的,我们可以通过以下命令安装工作流包: ```python pip install llama-index-utils-workflow ```
我们可以通过定义一个继承自 `Workflow` 的类并用 `@step` 装饰你的函数来创建一个单步工作流。 我们还需要添加 `StartEvent` 和 `StopEvent`,它们是用于指示工作流开始和结束的特殊事件。 ```python from llama_index.core.workflow import StartEvent, StopEvent, Workflow, step class MyWorkflow(Workflow): @step async def my_step(self, ev: StartEvent) -> StopEvent: # do something here return StopEvent(result="Hello, world!") w = MyWorkflow(timeout=10, verbose=False) result = await w.run() ``` 如您所见,我们现在可以通过调用“w.run()”来运行工作流程。 ### 连接多个步骤 为了连接多个步骤,我们**创建在步骤之间传输数据的自定义事件**。 为此,我们需要添加一个在步骤之间传递的“事件”,并将第一步的输出传输到第二步。 ```python from llama_index.core.workflow import Event class ProcessingEvent(Event): intermediate_result: str class MultiStepWorkflow(Workflow): @step async def step_one(self, ev: StartEvent) -> ProcessingEvent: # Process initial data return ProcessingEvent(intermediate_result="Step 1 complete") @step async def step_two(self, ev: ProcessingEvent) -> StopEvent: # Use the intermediate result final_result = f"Finished processing: {ev.intermediate_result}" return StopEvent(result=final_result) w = MultiStepWorkflow(timeout=10, verbose=False) result = await w.run() result ``` 类型提示在这里很重要,因为它可以确保工作流正确执行。让我们把事情复杂化一点吧! ### 循环和分支 类型提示是工作流中最强大的部分,因为它允许我们创建分支、循环和连接以促进更复杂的工作流。 让我们展示一个使用联合运算符 `|` **创建循环** 的示例。 在下面的示例中,我们看到 `LoopEvent` 被作为步骤的输入,也可以作为输出返回。 ```python from llama_index.core.workflow import Event import random class ProcessingEvent(Event): intermediate_result: str class LoopEvent(Event): loop_output: str class MultiStepWorkflow(Workflow): @step async def step_one(self, ev: StartEvent | LoopEvent) -> ProcessingEvent | LoopEvent: if random.randint(0, 1) == 0: print("Bad thing happened") return LoopEvent(loop_output="Back to step one.") else: print("Good thing happened") return ProcessingEvent(intermediate_result="First step complete.") @step async def step_two(self, ev: ProcessingEvent) -> StopEvent: # Use the intermediate result final_result = f"Finished processing: {ev.intermediate_result}" return StopEvent(result=final_result) w = MultiStepWorkflow(verbose=False) result = await w.run() result ``` ### 绘制工作流程 我们还可以绘制工作流程。让我们使用 `draw_all_possible_flows` 函数来绘制工作流程。这会将工作流程存储在 HTML 文件中。 ```python from llama_index.utils.workflow import draw_all_possible_flows w = ... # as defined in the previous section draw_all_possible_flows(w, "flow.html") ``` ![工作流程图](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/workflow-draw.png) 课程中我们将介绍最后一个很酷的技巧,即向工作流添加状态的能力。 ### 状态管理 当您想要跟踪工作流的状态时,状态管理非常有用,这样每个步骤都可以访问相同的状态。 我们可以在步骤函数中的参数上使用“上下文”类型提示来实现这一点。 ```python from llama_index.core.workflow import Context, StartEvent, StopEvent @step async def query(self, ctx: Context, ev: StartEvent) -> StopEvent: # 存储在上下文中 await ctx.store.set("query", "What is the capital of France?") # 根据上下文和事件做某事 val = ... # 从上下文中检索 query = await ctx.store.get("query") return StopEvent(result=result) ``` 太棒了!现在您知道如何在 LlamaIndex 中创建基本工作流了! > [!TIP] > 工作流还有一些更复杂的细微差别,您可以在LlamaIndex 文档中了解。 但是,还有另一种创建工作流的方法,它依赖于 `AgentWorkflow` 类。让我们看看如何使用它来创建多智能体工作流。 ## 使用多智能体工作流自动化工作流 我们可以使用**`AgentWorkflow` 类来创建多智能体工作流**,而无需手动创建工作流。 `AgentWorkflow` 使用工作流智能体,允许您创建一个或多个智能体的系统,这些智能体可以根据其专门功能进行协作并相互交接任务。 这可以构建复杂的智能体系统,其中不同的智能体处理任务的不同方面。 我们将从`llama_index.core.agent.workflow` 导入智能体类,而不是从`llama_index.core.agent` 导入类。 在`AgentWorkflow` 构造函数中,必须将一个智能体指定为根智能体。 当用户消息传入时,它首先被路由到根智能体。 然后每个智能体可以: - 使用他们的工具直接处理请求 - 交接给更适合该任务的另一个智能体 - 向用户返回响应 让我们看看如何创建多智能体工作流。 ```python from llama_index.core.agent.workflow import AgentWorkflow, ReActAgent from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI # 定义一些工具 def add(a: int, b: int) -> int: """Add two numbers.""" return a + b def multiply(a: int, b: int) -> int: """Multiply two numbers.""" return a * b llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") # 我们可以直接传递函数,而无需 FunctionTool——fn/docstring 会被解析为名称/描述 multiply_agent = ReActAgent( name="multiply_agent", description="Is able to multiply two integers", system_prompt="A helpful assistant that can use a tool to multiply numbers.", tools=[multiply], llm=llm, ) addition_agent = ReActAgent( name="add_agent", description="Is able to add two integers", system_prompt="A helpful assistant that can use a tool to add numbers.", tools=[add], llm=llm, ) # 创建工作流 workflow = AgentWorkflow( agents=[multiply_agent, addition_agent], root_agent="multiply_agent", ) # 运行系统 response = await workflow.run(user_msg="Can you add 5 and 3?") ``` 智能体工具还可以修改我们前面提到的工作流状态。在启动工作流之前,我们可以提供一个可供所有智能体使用的初始状态字典。 状态存储在工作流上下文的 state 键中。它将被注入到 state_prompt 中,以增强每个新用户消息。 让我们通过修改前面的示例来注入一个计数器来计数函数调用: ```python from llama_index.core.workflow import Context # 定义一些工具 async def add(ctx: Context, a: int, b: int) -> int: """Add two numbers.""" # update our count cur_state = await ctx.store.get("state") cur_state["num_fn_calls"] += 1 await ctx.store.set("state", cur_state) return a + b async def multiply(ctx: Context, a: int, b: int) -> int: """Multiply two numbers.""" # update our count cur_state = await ctx.store.get("state") cur_state["num_fn_calls"] += 1 await ctx.store.set("state", cur_state) return a * b ... workflow = AgentWorkflow( agents=[multiply_agent, addition_agent], root_agent="multiply_agent" initial_state={"num_fn_calls": 0}, state_prompt="Current state: {state}. User message: {msg}", ) # 使用上下文运行工作流程 ctx = Context(workflow) response = await workflow.run(user_msg="Can you add 5 and 3?", ctx=ctx) # 拉出并检查状态 state = await ctx.store.get("state") print(state["num_fn_calls"]) ``` 恭喜!您现在已经掌握了 LlamaIndex 中 Agent 的基础知识!🎉 让我们继续进行最后一次测验来巩固您的知识!🚀 ================================================ FILE: units/zh-CN/unit2/smolagents/code_agents.mdx ================================================ # 构建使用代码的智能体 代码智能体(Code agents)是 `smolagents` 中的默认智能体类型。它们生成 Python 工具调用来执行操作,实现高效、表达力强且准确的操作表示。 它们的简化方法减少了所需操作的数量,简化了复杂操作,并实现了对现有代码函数的重用。`smolagents` 提供了一个轻量级框架,用约 1,000 行代码实现构建代码智能体(code agents)。 ![代码与 JSON 操作对比](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/code_vs_json_actions.png) 图片来自论文 [Executable Code Actions Elicit Better LLM Agents](https://huggingface.co/papers/2402.01030) > [!TIP] > 如果你想了解更多关于为什么代码智能体如此有效的信息,请查看 smolagents 文档中的这个指南。 ## 为什么选择代码智能体? 在多步骤智能体过程中,大语言模型(LLM)编写并执行操作,通常涉及外部工具调用。传统方法使用 JSON 格式来指定工具名称和参数作为字符串,**系统必须解析这些内容以确定要执行哪个工具**。 然而,研究表明,**工具调用型大语言模型直接使用代码工作更有效**。这是 `smolagents` 的核心原则,如上图所示,来自论文 [Executable Code Actions Elicit Better LLM Agents](https://huggingface.co/papers/2402.01030)。 用代码而非 JSON 编写操作提供了几个关键优势: * **可组合性(Composability)**:轻松组合和重用操作 * **对象管理(Object Management)**:直接处理复杂结构,如图像 * **通用性(Generality)**:表达任何计算上可能的任务 * **适合大语言模型**:高质量代码已存在于大语言模型的训练数据中 ## 代码智能体如何工作? ![来自 https://huggingface.co/docs/smolagents/conceptual_guides/react](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/smolagents/codeagent_docs.png) 上图说明了 `CodeAgent.run()` 如何操作,遵循我们在第 1 单元中提到的 ReAct 框架。`smolagents` 中智能体的主要抽象是 `MultiStepAgent`,它作为核心构建块。如我们将在下面的示例中看到的,`CodeAgent` 是一种特殊的 `MultiStepAgent`。 `CodeAgent` 通过一系列步骤执行操作,将现有变量和知识整合到智能体的上下文中,这些内容保存在执行日志中: 1. 系统提示存储在 `SystemPromptStep` 中,用户查询记录在 `TaskStep` 中。 2. 然后,执行以下循环: 2.1 方法 `agent.write_memory_to_messages()` 将智能体的日志写入大语言模型可读的[聊天消息](https://huggingface.co/docs/transformers/en/chat_templating)列表中。 2.2 这些消息发送给 `Model`,生成补全(completion)。 2.3 解析补全内容以提取操作,在我们的例子中,这应该是代码片段,因为我们使用的是 `CodeAgent`。 2.4 执行该操作。 2.5 将结果记录到内存中的 `ActionStep` 中。 在每个步骤结束时,如果智能体包含任何函数调用(在 `agent.step_callback` 中),它们将被执行。 ## 让我们看一些例子 > [!TIP] > 你可以在 这个笔记本 中跟随代码,可以使用 Google Colab 运行。 阿尔弗雷德(Alfred)正在韦恩家族大宅计划一场派对,需要你的帮助确保一切顺利进行。为了帮助他,我们将应用我们所学到的关于多步骤 `CodeAgent` 如何运作的知识。 Alfred 派对 如果你还没有安装 `smolagents`,可以运行以下命令进行安装: ```bash pip install smolagents -U ``` 让我们也登录到 Hugging Face Hub,以便访问无服务器推理 API(Serverless Inference API)。 ```python from huggingface_hub import login login() ``` ### 使用 `smolagents` 为派对选择播放列表 音乐是成功派对的重要组成部分!阿尔弗雷德需要一些帮助来选择播放列表。幸运的是,`smolagents` 能够帮助我们!我们可以构建一个能够使用 DuckDuckGo 搜索网络的智能体。要让智能体访问此工具,我们在创建智能体时将其包含在工具列表中。 Alfred 播放列表 对于模型,我们将依赖 `InferenceClientModel`,它提供对 Hugging Face 的[无服务器推理 API](https://huggingface.co/docs/api-inference/index)的访问。默认模型是 `"Qwen/Qwen2.5-Coder-32B-Instruct"`,它性能良好并可用于快速推理,但你可以从 Hub 中选择任何兼容的模型。 运行智能体相当简单: ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel agent = CodeAgent(tools=[DuckDuckGoSearchTool()], model=InferenceClientModel()) agent.run("Search for the best music recommendations for a party at the Wayne's mansion.") ``` 当你运行这个例子时,输出将**显示正在执行的工作流步骤的跟踪**。它还会打印相应的 Python 代码,并附带消息: ```python ─ Executing parsed code: ──────────────────────────────────────────────────────────────────────────────────────── results = web_search(query="best music for a Batman party") print(results) ───────────────────────────────────────────────────────────────────────────────────────────────────────────────── ``` 几个步骤后,你将看到阿尔弗雷德可以用于派对的生成播放列表!🎵 ### 使用自定义工具准备菜单 Alfred 菜单 现在我们已经选择了播放列表,我们需要为客人组织菜单。同样,阿尔弗雷德可以利用 `smolagents` 来做到这一点。在这里,我们使用 `@tool` 装饰器定义一个作为工具的自定义函数。我们稍后将更详细地介绍工具创建,所以现在我们可以简单地运行代码。 如下例所示,我们将使用 `@tool` 装饰器创建一个工具,并将其包含在 `tools` 列表中。 ```python from smolagents import CodeAgent, tool, InferenceClientModel # 根据场合建议菜单的工具 @tool def suggest_menu(occasion: str) -> str: """ Suggests a menu based on the occasion. Args: occasion: The type of occasion for the party. """ if occasion == "casual": return "Pizza, snacks, and drinks." elif occasion == "formal": return "3-course dinner with wine and dessert." elif occasion == "superhero": return "Buffet with high-energy and healthy food." else: return "Custom menu for the butler." # 管家阿尔弗雷德,为派对准备菜单 agent = CodeAgent(tools=[suggest_menu], model=InferenceClientModel()) # 为派对准备正式菜单 agent.run("Prepare a formal menu for the party.") ``` 智能体将运行几个步骤,直到找到答案。 菜单准备好了!🥗 ### 在智能体内部使用 Python 导入 我们已经准备好了播放列表和菜单,但我们需要检查另一个关键细节:准备时间! 阿尔弗雷德需要计算如果他现在开始准备,什么时候一切都会准备就绪,以防他们需要其他超级英雄的帮助。 `smolagents` 专门用于编写和执行 Python 代码片段的智能体,处于安全方面的考量,其提供沙盒执行环境。 **代码执行有严格的安全措施** - 默认情况下,预定义安全列表之外的导入被阻止。但是,您可以通过将它们作为字符串传递到 `additional_authorized_imports` 中来授权额外的导入。 有关安全代码执行的更多详情,请参阅官方[指南](https://huggingface.co/docs/smolagents/tutorials/secure_code_execution)。 创建智能体时,我们将使用 `additional_authorized_imports` 来允许导入 `datetime` 模块。 ```python from smolagents import CodeAgent, InferenceClientModel import numpy as np import time import datetime agent = CodeAgent(tools=[], model=InferenceClientModel(), additional_authorized_imports=['datetime']) agent.run( """ Alfred needs to prepare for the party. Here are the tasks: 1. Prepare the drinks - 30 minutes 2. Decorate the mansion - 60 minutes 3. Set up the menu - 45 minutes 3. Prepare the music and playlist - 45 minutes If we start right now, at what time will the party be ready? """ ) ``` 这些例子只是代码智能体能做的事情的开始,我们已经开始看到它们对准备派对的实用性。 你可以在 [smolagents 文档](https://huggingface.co/docs/smolagents) 中了解更多关于如何构建代码智能体的信息。 总之,`smolagents` 专注于编写和执行 Python 代码片段的智能体,提供安全的沙盒执行环境。它支持本地和基于 API 的语言模型,使其适应各种开发环境。 ### 将我们的自定义派对准备智能体分享到 Hub **将我们自己的阿尔弗雷德智能体与社区分享**难道不会很棒吗?通过这样做,任何人都可以轻松地从 Hub 下载并直接使用这个智能体,将哥谭市的终极派对策划者带到他们的指尖!让我们实现这个想法!🎉 `smolagents` 库使这成为可能,允许你与社区分享完整的智能体,并下载其他人的智能体立即使用。这很简单,如下所示: ```python # 更改为你的用户名和仓库名 agent.push_to_hub('sergiopaniego/AlfredAgent') ``` 要再次下载智能体,请使用以下代码: ```python # 更改为你的用户名和仓库名 alfred_agent = agent.from_hub('sergiopaniego/AlfredAgent') alfred_agent.run("Give me the best playlist for a party at Wayne's mansion. The party idea is a 'villain masquerade' theme") ``` 令人兴奋的是,共享的智能体直接作为 Hugging Face Spaces 提供,允许你实时与它们交互。你可以在[这里](https://huggingface.co/spaces/davidberenstein1957/smolagents-and-tools)探索其他智能体。 例如,_AlfredAgent_ 在[这里](https://huggingface.co/spaces/sergiopaniego/AlfredAgent)可用。你可以直接在下面尝试: 你可能想知道——阿尔弗雷德如何使用 `smolagents` 构建这样一个智能体?通过整合几个工具,他可以生成一个如下的智能体。现在不用担心这些工具,因为我们将在本单元后面有专门的部分详细探讨: ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, FinalAnswerTool, InferenceClientModel, Tool, tool, VisitWebpageTool @tool def suggest_menu(occasion: str) -> str: """ Suggests a menu based on the occasion. Args: occasion: The type of occasion for the party. """ if occasion == "casual": return "Pizza, snacks, and drinks." elif occasion == "formal": return "3-course dinner with wine and dessert." elif occasion == "superhero": return "Buffet with high-energy and healthy food." else: return "Custom menu for the butler." @tool def catering_service_tool(query: str) -> str: """ This tool returns the highest-rated catering service in Gotham City. Args: query: A search term for finding catering services. """ # 餐饮服务及其评分的示例列表 services = { "Gotham Catering Co.": 4.9, "Wayne Manor Catering": 4.8, "Gotham City Events": 4.7, } # 找到评分最高的餐饮服务(模拟搜索查询过滤) best_service = max(services, key=services.get) return best_service class SuperheroPartyThemeTool(Tool): name = "superhero_party_theme_generator" description = """ This tool suggests creative superhero-themed party ideas based on a category. It returns a unique party theme idea.""" inputs = { "category": { "type": "string", "description": "The type of superhero party (e.g., 'classic heroes', 'villain masquerade', 'futuristic Gotham').", } } output_type = "string" def forward(self, category: str): themes = { "classic heroes": "Justice League Gala: Guests come dressed as their favorite DC heroes with themed cocktails like 'The Kryptonite Punch'.", "villain masquerade": "Gotham Rogues' Ball: A mysterious masquerade where guests dress as classic Batman villains.", "futuristic Gotham": "Neo-Gotham Night: A cyberpunk-style party inspired by Batman Beyond, with neon decorations and futuristic gadgets." } return themes.get(category.lower(), "Themed party idea not found. Try 'classic heroes', 'villain masquerade', or 'futuristic Gotham'.") # 管家阿尔弗雷德,为派对准备菜单 agent = CodeAgent( tools=[ DuckDuckGoSearchTool(), VisitWebpageTool(), suggest_menu, catering_service_tool, SuperheroPartyThemeTool() ], model=InferenceClientModel(), max_steps=10, verbosity_level=2 ) agent.run("Give me best playlist for a party at the Wayne's mansion. The party idea is a 'villain masquerade' theme") ``` 如你所见,我们创建了一个具有多种工具的 `CodeAgent`,这些工具增强了智能体的功能,将其变成了准备好与社区分享的终极派对策划者!🎉 现在,轮到你了:使用我们刚刚学到的知识,构建你自己的智能体并与社区分享!🕵️‍♂️💡 > [!TIP] > 如果你想分享你的智能体项目,请创建一个 space 并在 Hugging Face Hub 上标记 [agents-course](https://huggingface.co/agents-course)。我们很想看看你创造了什么! ### 使用 OpenTelemetry 和 Langfuse 检查我们的派对准备智能体 📡 随着阿尔弗雷德对派对准备智能体的微调,他对调试其运行越来越疲惫。智能体本质上是不可预测的,难以检查。但由于他的目标是构建终极派对准备智能体并将其部署到生产环境中,他需要强大的可追踪性,用于未来的监控和分析。 再一次,`smolagents` 来救援!它采用 [OpenTelemetry](https://opentelemetry.io/) 标准来检测智能体运行,允许无缝检查和日志记录。在 [Langfuse](https://langfuse.com/) 和 `SmolagentsInstrumentor` 的帮助下,阿尔弗雷德可以轻松跟踪和分析他的智能体行为。 设置非常简单! 首先,我们需要安装必要的依赖项: ```bash pip install opentelemetry-sdk opentelemetry-exporter-otlp openinference-instrumentation-smolagents langfuse ``` 接下来,阿尔弗雷德已经在 Langfuse 上创建了一个账户,并准备好了他的 API 密钥。如果你还没有这样做,你可以在[这里](https://cloud.langfuse.com/)注册 Langfuse Cloud 或探索[替代方案](https://huggingface.co/docs/smolagents/tutorials/inspect_runs)。 一旦你有了 API 密钥,它们需要正确配置如下: ```python import os # Get keys for your project from the project settings page: https://cloud.langfuse.com os.environ["LANGFUSE_PUBLIC_KEY"] = "pk-lf-..." os.environ["LANGFUSE_SECRET_KEY"] = "sk-lf-..." os.environ["LANGFUSE_HOST"] = "https://cloud.langfuse.com" # 🇪🇺 EU region # os.environ["LANGFUSE_HOST"] = "https://us.cloud.langfuse.com" # 🇺🇸 US region ``` With the environment variables set, we can now initialize the Langfuse client. get_client() initializes the Langfuse client using the credentials provided in the environment variables. ```python from langfuse import get_client langfuse = get_client() # Verify connection if langfuse.auth_check(): print("Langfuse client is authenticated and ready!") else: print("Authentication failed. Please check your credentials and host.") ``` 最后,阿尔弗雷德准备初始化 `SmolagentsInstrumentor` 并开始跟踪他的智能体性能。 ```python from openinference.instrumentation.smolagents import SmolagentsInstrumentor SmolagentsInstrumentor().instrument() ``` 阿尔弗雷德现在已连接 🔌!来自 `smolagents` 的运行正在 Langfuse 中记录,让他完全可见智能体的行为。有了这个设置,他准备重新访问之前的运行并进一步改进他的派对准备智能体。 ```python from smolagents import CodeAgent, InferenceClientModel agent = CodeAgent(tools=[], model=InferenceClientModel()) alfred_agent = agent.from_hub('sergiopaniego/AlfredAgent', trust_remote_code=True) alfred_agent.run("Give me the best playlist for a party at Wayne's mansion. The party idea is a 'villain masquerade' theme") ``` 阿尔弗雷德现在可以在[这里](https://cloud.langfuse.com/project/cm7bq0abj025rad078ak3luwi/traces/995fc019255528e4f48cf6770b0ce27b?timestamp=2025-02-19T10%3A28%3A36.929Z)访问这些日志来审查和分析它们。 同时,[建议的播放列表](https://open.spotify.com/playlist/0gZMMHjuxMrrybQ7wTMTpw)为派对准备设置了完美的氛围。很酷,对吧?🎶 --- 现在我们已经创建了我们的第一个代码智能体,让我们**学习如何创建工具调用智能体(Tool Calling Agents)**,这是 `smolagents` 中可用的第二种智能体类型。 ## 资源 - [smolagents 博客](https://huggingface.co/blog/smolagents) - smolagents 和代码交互介绍 - [smolagents:构建好的智能体](https://huggingface.co/docs/smolagents/tutorials/building_good_agents) - 可靠智能体的最佳实践 - [构建有效的智能体 - Anthropic](https://www.anthropic.com/research/building-effective-agents) - 智能体设计原则 - [使用 OpenTelemetry 共享运行](https://huggingface.co/docs/smolagents/tutorials/inspect_runs) - 关于如何为跟踪你的智能体设置 OpenTelemetry 的详细信息 ================================================ FILE: units/zh-CN/unit2/smolagents/conclusion.mdx ================================================ # 结论 恭喜你完成了第二单元的 `smolagents` 模块 🥳 你刚刚掌握了 `smolagents` 的基础知识,并且构建了自己的智能体!现在你已经具备了 `smolagents` 的技能,你可以开始创建能够解决你感兴趣任务的智能体。 在下一个模块中,你将学习**如何使用 LlamaIndex 构建智能体(Agents)**。 最后,我们非常想**听听你对这门课程的看法以及我们如何改进它**。如果你有任何反馈,请👉 [填写这个表格](https://docs.google.com/forms/d/e/1FAIpQLSe9VaONn0eglax0uTwi29rIn4tM7H2sYmmybmG5jJNlE5v0xA/viewform?usp=dialog) ### 继续学习,保持优秀 🤗 ================================================ FILE: units/zh-CN/unit2/smolagents/final_quiz.mdx ================================================ # 测验时间! 恭喜你完成了 `smolagents` 的学习材料!你已经取得了很多成就。现在,是时候通过一个测验来测试你的知识了。🧠 ## 说明 - 测验由代码问题组成。 - 你将得到完成代码片段的指示。 - 仔细阅读指示并相应地完成代码片段。 - 对于每个问题,你将得到结果和一些反馈。 🧘 **这个测验不计分也不提供证书**。这是关于你理解 `smolagents` 库,并了解你是否应该在书面材料上花更多时间。在接下来的单元中,你将在用例和项目中测试这些知识。 让我们开始吧! ## 测验 🚀 你也可以点击👉 [这里](https://huggingface.co/spaces/agents-course/unit2_smolagents_quiz) 访问测验 ================================================ FILE: units/zh-CN/unit2/smolagents/introduction.mdx ================================================ # `smolagents` 简介 Unit 2.1 Thumbnail 欢迎来到本模块,在这里你将学习**如何使用 [`smolagents`](https://github.com/huggingface/smolagents) 库构建有效的智能体**,该库提供了一个轻量级框架,用于创建功能强大的AI智能体。 `smolagents` 是 Hugging Face 的一个库;因此,我们非常感谢您通过**加星标**的方式支持 smolagents [`仓库`](https://github.com/huggingface/smolagents): staring smolagents ## 模块概览 本模块提供了使用 `smolagents` 构建智能体的关键概念和实用策略的全面概述。 面对众多可用的开源框架,了解使 `smolagents` 成为有用选择的组件和功能,或确定何时另一种解决方案可能更合适,这一点至关重要。 我们将探索关键的智能体类型,包括为软件开发任务设计的代码智能体(code agents),用于创建模块化、函数驱动工作流的工具调用智能体(tool calling agents),以及访问和综合信息的检索智能体(retrieval agents)。 此外,我们还将讨论多个智能体的编排,以及视觉能力和网络浏览的集成,这为动态和上下文感知应用开辟了新的可能性。 在本单元中,第一单元的智能体阿尔弗雷德(Alfred)回归了。这次,他使用 `smolagents` 框架进行内部运作。我们将一起探索这个框架背后的关键概念,同时阿尔弗雷德将处理各种任务。阿尔弗雷德正在韦恩庄园(Wayne Manor)组织一场派对,趁韦恩家族🦇外出时,他有很多事情要做。跟随我们一起展示他的旅程,看他如何使用 `smolagents` 处理这些任务! > [!TIP] > 在本单元中,您将学习使用 `smolagents` 库构建AI智能体。您的智能体将能够搜索数据、执行代码并与网页交互。您还将学习如何结合多个智能体来创建更强大的系统。 ![Alfred the agent](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit1/this-is-alfred.jpg) ## 内容 在这个关于 `smolagents` 的单元中,我们涵盖: ### 1️⃣ [为什么使用 smolagents](./why_use_smolagents) `smolagents` 是众多可用于应用程序开发的开源智能体框架之一。其他选择包括 `LlamaIndex` 和 `LangGraph`,这些在本课程的其他模块中也有涵盖。`smolagents` 提供了几个关键特性,可能使其非常适合特定用例,但在选择框架时,我们应该始终考虑所有选项。我们将探讨使用 `smolagents` 的优势和缺点,帮助您根据项目需求做出明智的决定。 ### 2️⃣ [代码智能体](./code_agents) `CodeAgents`(代码智能体)是 `smolagents` 中的主要智能体类型。这些智能体不是生成 JSON 或文本,而是生成 Python 代码来执行操作。本模块探讨它们的目的、功能以及工作原理,并提供实际例子来展示它们的能力。 ### 3️⃣ [工具调用智能体](./tool_calling_agents) `ToolCallingAgents`(工具调用智能体)是 `smolagents` 支持的第二种智能体类型。与生成 Python 代码的 `CodeAgents` 不同,这些智能体依赖于系统必须解析和解释以执行操作的 JSON/文本块。本模块涵盖它们的功能、与 `CodeAgents` 的主要区别,并提供示例说明其用法。 ### 4️⃣ [工具](./tools) 正如我们在第 1 单元中看到的,工具是大语言模型(LLM)可以在智能体系统中使用的函数,它们作为智能体行为的基本构建块。本模块涵盖如何创建工具、它们的结构,以及使用 `Tool` 类或 `@tool` 装饰器的不同实现方法。您还将了解默认工具箱、如何与社区共享工具,以及如何加载社区贡献的工具以在您的智能体中使用。 ### 5️⃣ [检索智能体](./retrieval_agents) 检索智能体(Retrieval agents)使模型能够访问知识库,从而可以从多个来源搜索、综合和检索信息。它们利用向量存储(vector stores)进行高效检索,并实现 **检索增强生成(Retrieval-Augmented Generation,RAG)** 模式。这些智能体特别适用于将网络搜索与自定义知识库集成,同时通过记忆系统维持对话上下文。本模块探讨实施策略,包括用于稳健信息检索的回退机制。 ### 6️⃣ [多智能体系统](./multi_agent_systems) 有效地编排多个智能体对于构建强大的多智能体系统至关重要。通过组合具有不同能力的智能体(例如,将网络搜索智能体与代码执行智能体结合),您可以创建更复杂的解决方案。本模块专注于设计、实施和管理多智能体系统,以最大限度地提高效率和可靠性。 ### 7️⃣ [视觉和浏览器智能体](./vision_agents) 视觉智能体(Vision agents)通过整合 **视觉-语言模型(Vision-Language Models,VLMs)** 扩展了传统智能体的能力,使其能够处理和解释视觉信息。本模块探讨如何设计和集成由 VLM 驱动的智能体,从而解锁诸如基于图像的推理、视觉数据分析和多模态交互等高级功能。我们还将使用视觉智能体构建一个浏览器智能体,能够浏览网络并从中提取信息。 ## 资源 - [smolagents 文档](https://huggingface.co/docs/smolagents) - smolagents 库的官方文档 - [构建有效的智能体](https://www.anthropic.com/research/building-effective-agents) - 关于智能体架构的研究论文 - [智能体指南](https://huggingface.co/docs/smolagents/tutorials/building_good_agents) - 构建可靠智能体的最佳实践 - [LangGraph 智能体](https://langchain-ai.github.io/langgraph/) - 智能体实现的其他示例 - [函数调用指南](https://platform.openai.com/docs/guides/function-calling) - 了解大语言模型中的函数调用 - [RAG 最佳实践](https://www.pinecone.io/learn/retrieval-augmented-generation/) - 实施有效 RAG 的指南 ================================================ FILE: units/zh-CN/unit2/smolagents/multi_agent_systems.mdx ================================================ # 多智能体系统 多智能体系统使**专业智能体能够在复杂任务上进行协作**,提高模块化、可扩展性和稳健性。不依赖单一智能体,任务分配给具有不同能力的智能体。 在 **smolagents** 中,不同的智能体可以组合起来生成 Python 代码、调用外部工具、执行网络搜索等。通过编排这些智能体,我们可以创建强大的工作流。 一个典型的设置可能包括: - **管理智能体(Manager Agent)** 用于任务委派 - **代码解释器智能体(Code Interpreter Agent)** 用于代码执行 - **网络搜索智能体(Web Search Agent)** 用于信息检索 下图说明了一个简单的多智能体架构,其中**管理智能体**协调**代码解释器工具**和**网络搜索智能体**,后者利用像 `DuckDuckGoSearchTool` 和 `VisitWebpageTool` 这样的工具来收集相关信息。 ## 多智能体系统实战 多智能体系统由多个专业智能体在 **编排智能体(Orchestrator Agent)** 的协调下共同工作组成。这种方法通过在具有不同角色的智能体之间分配任务来实现复杂的工作流。 例如,**多智能体 RAG 系统**可以整合: - **网络智能体(Web Agent)** 用于浏览互联网。 - **检索智能体(Retriever Agent)** 用于从知识库获取信息。 - **图像生成智能体(Image Generation Agent)** 用于生成视觉内容。 所有这些智能体在管理任务委派和交互的编排者下运行。 ## 用多智能体层次结构解决复杂任务 > [!TIP] > 你可以在{" "} > href="https://huggingface.co/agents-course/notebooks/blob/main/unit2/smolagents/multiagent_notebook.ipynb" > target="_blank" > > > 这个笔记本 > {" "} > 中跟随代码,可以使用 Google Colab 运行。 接待会即将到来!在你的帮助下,阿尔弗雷德现在几乎完成了准备工作。 但现在有个问题:蝙蝠车不见了。阿尔弗雷德需要找到替代品,而且要快。 幸运的是,已经有一些关于布鲁斯·韦恩生活的传记电影,所以也许阿尔弗雷德可以从某个电影拍摄现场留下的汽车中获取一辆,并将其重新改造到现代标准,这当然会包括完全自动驾驶选项。 但这可能在世界各地的任何拍摄地点——可能数量众多。 所以阿尔弗雷德需要你的帮助。你能构建一个能够解决这个任务的智能体吗? > 👉 Find all Batman filming locations in the world, calculate the time to transfer via boat to there, and represent them on a map, with a color varying by boat transfer time. Also represent some supercar factories with the same boat transfer time. 让我们来构建这个! 这个例子需要一些额外的包,所以首先安装它们: ```bash pip install 'smolagents[litellm]' matplotlib geopandas shapely kaleido -q ``` ### 我们首先制作一个工具来获取货运飞机转运时间。 ```python import math from typing import Optional, Tuple from smolagents import tool @tool def calculate_cargo_travel_time( origin_coords: Tuple[float, float], destination_coords: Tuple[float, float], cruising_speed_kmh: Optional[float] = 750.0, # 货运飞机的平均速度 ) -> float: """ Calculate the travel time for a cargo plane between two points on Earth using great-circle distance. Args: origin_coords: Tuple of (latitude, longitude) for the starting point destination_coords: Tuple of (latitude, longitude) for the destination cruising_speed_kmh: Optional cruising speed in km/h (defaults to 750 km/h for typical cargo planes) Returns: float: The estimated travel time in hours Example: >>> # Chicago (41.8781° N, 87.6298° W) to Sydney (33.8688° S, 151.2093° E) >>> result = calculate_cargo_travel_time((41.8781, -87.6298), (-33.8688, 151.2093)) """ def to_radians(degrees: float) -> float: return degrees * (math.pi / 180) # 提取坐标 lat1, lon1 = map(to_radians, origin_coords) lat2, lon2 = map(to_radians, destination_coords) # 地球半径(公里) EARTH_RADIUS_KM = 6371.0 # 使用半正矢公式计算大圆距离 dlon = lon2 - lon1 dlat = lat2 - lat1 a = ( math.sin(dlat / 2) ** 2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2) ** 2 ) c = 2 * math.asin(math.sqrt(a)) distance = EARTH_RADIUS_KM * c # 增加10%以考虑非直接路线和空中交通管制 actual_distance = distance * 1.1 # 计算飞行时间 # 为起飞和着陆程序增加1小时 flight_time = (actual_distance / cruising_speed_kmh) + 1.0 # 格式化结果 return round(flight_time, 2) print(calculate_cargo_travel_time((41.8781, -87.6298), (-33.8688, 151.2093))) ``` ### 设置智能体 对于模型提供商,我们使用 Together AI,这是 [Hub 上的新推理提供商](https://huggingface.co/blog/inference-providers)之一! GoogleSearchTool 使用 [Serper API](https://serper.dev) 搜索网络,因此这需要设置环境变量 `SERPAPI_API_KEY` 并传递 `provider="serpapi"` 或者拥有 `SERPER_API_KEY` 并传递 `provider=serper`。 如果你没有设置任何 Serp API 提供商,你可以使用 `DuckDuckGoSearchTool`,但请注意它有速率限制。 ```python import os from PIL import Image from smolagents import CodeAgent, GoogleSearchTool, InferenceClientModel, VisitWebpageTool model = InferenceClientModel(model_id="Qwen/Qwen2.5-Coder-32B-Instruct", provider="together") ``` 我们可以先创建一个简单的智能体作为基线,为我们提供一个简单的报告。 ```python task = """Find all Batman filming locations in the world, calculate the time to transfer via cargo plane to here (we're in Gotham, 40.7128° N, 74.0060° W), and return them to me as a pandas dataframe. Also give me some supercar factories with the same cargo plane transfer time.""" ``` ```python agent = CodeAgent( model=model, tools=[GoogleSearchTool("serper"), VisitWebpageTool(), calculate_cargo_travel_time], additional_authorized_imports=["pandas"], max_steps=20, ) ``` ```python result = agent.run(task) ``` ```python result ``` 在我们的例子中,它生成了这个输出: ```python | | Location | Travel Time to Gotham (hours) | |--|------------------------------------------------------|------------------------------| | 0 | Necropolis Cemetery, Glasgow, Scotland, UK | 8.60 | | 1 | St. George's Hall, Liverpool, England, UK | 8.81 | | 2 | Two Temple Place, London, England, UK | 9.17 | | 3 | Wollaton Hall, Nottingham, England, UK | 9.00 | | 4 | Knebworth House, Knebworth, Hertfordshire, UK | 9.15 | | 5 | Acton Lane Power Station, Acton Lane, Acton, UK | 9.16 | | 6 | Queensboro Bridge, New York City, USA | 1.01 | | 7 | Wall Street, New York City, USA | 1.00 | | 8 | Mehrangarh Fort, Jodhpur, Rajasthan, India | 18.34 | | 9 | Turda Gorge, Turda, Romania | 11.89 | | 10 | Chicago, USA | 2.68 | | 11 | Hong Kong, China | 19.99 | | 12 | Cardington Studios, Northamptonshire, UK | 9.10 | | 13 | Warner Bros. Leavesden Studios, Hertfordshire, UK | 9.13 | | 14 | Westwood, Los Angeles, CA, USA | 6.79 | | 15 | Woking, UK (McLaren) | 9.13 | ``` 我们可以通过添加一些专门的规划步骤和更多的提示来进一步改进这一点。 规划步骤允许智能体提前思考并规划其下一步行动,这对于更复杂的任务非常有用。 ```python agent.planning_interval = 4 detailed_report = agent.run(f""" You're an expert analyst. You make comprehensive reports after visiting many websites. Don't hesitate to search for many queries at once in a for loop. For each data point that you find, visit the source url to confirm numbers. {task} """) print(detailed_report) ``` ```python detailed_report ``` 在我们的例子中,它生成了这个输出: ```python | | Location | Travel Time (hours) | |--|--------------------------------------------------|---------------------| | 0 | Bridge of Sighs, Glasgow Necropolis, Glasgow, UK | 8.6 | | 1 | Wishart Street, Glasgow, Scotland, UK | 8.6 | ``` 感谢这些快速更改,我们通过简单地为我们的智能体提供详细提示,并赋予它规划能力,获得了更加简洁的报告! 模型的上下文窗口正在快速填满。所以**如果我们要求我们的智能体将详细搜索的结果与另一个结合起来,它将变得更慢,并且会迅速增加 token 数量和成本**。 ➡️ 我们需要改进系统的结构。 ### ✌️ 在两个智能体之间分割任务 多智能体结构允许在不同子任务之间分离记忆,带来两大好处: - 每个智能体更专注于其核心任务,因此性能更佳 - 分离记忆减少了每个步骤的输入 token 数量,从而减少延迟和成本。 让我们创建一个团队,包含一个专门的网络搜索智能体,由另一个智能体管理。 管理智能体应该具有绘图功能来编写其最终报告:因此让我们给它访问额外导入的权限,包括 `matplotlib` 和 `geopandas` + `shapely` 用于空间绘图。 ```python model = InferenceClientModel( "Qwen/Qwen2.5-Coder-32B-Instruct", provider="together", max_tokens=8096 ) web_agent = CodeAgent( model=model, tools=[ GoogleSearchTool(provider="serper"), VisitWebpageTool(), calculate_cargo_travel_time, ], name="web_agent", description="Browses the web to find information", verbosity_level=0, max_steps=10, ) ``` 管理智能体需要进行一些较重的思考工作。 所以我们给它更强大的模型 [DeepSeek-R1](https://huggingface.co/deepseek-ai/DeepSeek-R1),并添加 `planning_interval` 到组合中。 ```python from smolagents.utils import encode_image_base64, make_image_url from smolagents import OpenAIServerModel def check_reasoning_and_plot(final_answer, agent_memory): final_answer multimodal_model = OpenAIServerModel("gpt-4o", max_tokens=8096) filepath = "saved_map.png" assert os.path.exists(filepath), "Make sure to save the plot under saved_map.png!" image = Image.open(filepath) prompt = ( f"Here is a user-given task and the agent steps: {agent_memory.get_succinct_steps()}. Now here is the plot that was made." "Please check that the reasoning process and plot are correct: do they correctly answer the given task?" "First list reasons why yes/no, then write your final decision: PASS in caps lock if it is satisfactory, FAIL if it is not." "Don't be harsh: if the plot mostly solves the task, it should pass." "To pass, a plot should be made using px.scatter_map and not any other method (scatter_map looks nicer)." ) messages = [ { "role": "user", "content": [ { "type": "text", "text": prompt, }, { "type": "image_url", "image_url": {"url": make_image_url(encode_image_base64(image))}, }, ], } ] output = multimodal_model(messages).content print("Feedback: ", output) if "FAIL" in output: raise Exception(output) return True manager_agent = CodeAgent( model=InferenceClientModel("deepseek-ai/DeepSeek-R1", provider="together", max_tokens=8096), tools=[calculate_cargo_travel_time], managed_agents=[web_agent], additional_authorized_imports=[ "geopandas", "plotly", "shapely", "json", "pandas", "numpy", ], planning_interval=5, verbosity_level=2, final_answer_checks=[check_reasoning_and_plot], max_steps=15, ) ``` 让我们检查这个团队是什么样子: ```python manager_agent.visualize() ``` 这将生成类似于下面的内容,帮助我们理解智能体和使用的工具之间的结构和关系: ```python CodeAgent | deepseek-ai/DeepSeek-R1 ├── ✅ Authorized imports: ['geopandas', 'plotly', 'shapely', 'json', 'pandas', 'numpy'] ├── 🛠️ Tools: │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ │ ┃ Name ┃ Description ┃ Arguments ┃ │ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ │ calculate_cargo_travel_time │ Calculate the travel time for a cargo │ origin_coords (`array`): Tuple of │ │ │ │ plane between two points on Earth │ (latitude, longitude) for the │ │ │ │ using great-circle distance. │ starting point │ │ │ │ │ destination_coords (`array`): Tuple │ │ │ │ │ of (latitude, longitude) for the │ │ │ │ │ destination │ │ │ │ │ cruising_speed_kmh (`number`): │ │ │ │ │ Optional cruising speed in km/h │ │ │ │ │ (defaults to 750 km/h for typical │ │ │ │ │ cargo planes) │ │ │ final_answer │ Provides a final answer to the given │ answer (`any`): The final answer to │ │ │ │ problem. │ the problem │ │ └─────────────────────────────┴───────────────────────────────────────┴───────────────────────────────────────┘ └── 🤖 Managed agents: └── web_agent | CodeAgent | Qwen/Qwen2.5-Coder-32B-Instruct ├── ✅ Authorized imports: [] ├── 📝 Description: Browses the web to find information └── 🛠️ Tools: ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ Name ┃ Description ┃ Arguments ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ web_search │ Performs a google web search for │ query (`string`): The search │ │ │ your query then returns a string │ query to perform. │ │ │ of the top search results. │ filter_year (`integer`): │ │ │ │ Optionally restrict results to a │ │ │ │ certain year │ │ visit_webpage │ Visits a webpage at the given url │ url (`string`): The url of the │ │ │ and reads its content as a │ webpage to visit. │ │ │ markdown string. Use this to │ │ │ │ browse webpages. │ │ │ calculate_cargo_travel_time │ Calculate the travel time for a │ origin_coords (`array`): Tuple of │ │ │ cargo plane between two points on │ (latitude, longitude) for the │ │ │ Earth using great-circle │ starting point │ │ │ distance. │ destination_coords (`array`): │ │ │ │ Tuple of (latitude, longitude) │ │ │ │ for the destination │ │ │ │ cruising_speed_kmh (`number`): │ │ │ │ Optional cruising speed in km/h │ │ │ │ (defaults to 750 km/h for typical │ │ │ │ cargo planes) │ │ final_answer │ Provides a final answer to the │ answer (`any`): The final answer │ │ │ given problem. │ to the problem │ └─────────────────────────────┴───────────────────────────────────┴───────────────────────────────────┘ ``` ```python manager_agent.run(""" Find all Batman filming locations in the world, calculate the time to transfer via cargo plane to here (we're in Gotham, 40.7128° N, 74.0060° W). Also give me some supercar factories with the same cargo plane transfer time. You need at least 6 points in total. Represent this as spatial map of the world, with the locations represented as scatter points with a color that depends on the travel time, and save it to saved_map.png! Here's an example of how to plot and return a map: import plotly.express as px df = px.data.carshare() fig = px.scatter_map(df, lat="centroid_lat", lon="centroid_lon", text="name", color="peak_hour", size=100, color_continuous_scale=px.colors.sequential.Magma, size_max=15, zoom=1) fig.show() fig.write_image("saved_image.png") final_answer(fig) Never try to process strings using code: when you have a string to read, just print it and you'll see it. """) ``` 我不知道在你的运行中情况如何,但在我的运行中,管理智能体巧妙地将任务分配给网络智能体,首先是 `1. Search for Batman filming locations`,然后是 `2. Find supercar factories`,最后聚合列表并绘制地图。 让我们通过直接从智能体状态查看地图: ```python manager_agent.python_executor.state["fig"] ``` 这将输出地图: ![多智能体系统示例输出地图](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/smolagents/output_map.png) ## 资源 - [多智能体系统](https://huggingface.co/docs/smolagents/main/en/examples/multiagents) – 多智能体系统概述。 - [什么是智能体 RAG?](https://weaviate.io/blog/what-is-agentic-rag) – 智能体 RAG 介绍。 - [多智能体 RAG 系统 🤖🤝🤖 配方](https://huggingface.co/learn/cookbook/multiagent_rag_system) – 构建多智能体 RAG 系统的分步指南。 ================================================ FILE: units/zh-CN/unit2/smolagents/quiz1.mdx ================================================ # 小测验 (不计分) [[quiz1]] 让我们用一个快速测验来测试你对 `smolagents` 的理解!请记住,自我测试有助于强化学习并识别可能需要复习的领域。 这是一个可选测验,不计分。 ### Q1: 选择 `smolagents` 而非其他框架的主要优势之一是什么? 哪个陈述最能体现 `smolagents` 方法的核心优势? --- ### Q2: 在哪种情况下,你可能最能从使用 smolagents 中受益? 哪种情况最符合 smolagents 的优势? --- ### Q3: smolagents 在模型集成方面提供了灵活性。哪个陈述最能反映其方法? 选择最准确描述 smolagents 如何与 LLM 互操作的说明。 --- ### Q4: smolagents 如何处理基于代码的操作和基于 JSON 的操作之间的争论? 哪个陈述正确地描述了 smolagents 关于操作格式的理念? --- ### Q5: smolagents 如何与 Hugging Face Hub 集成以获得额外优势? 哪个陈述准确描述了 Hub 集成的核心优势之一? --- 恭喜你完成了这个测验!🎉 如果你错过了任何问题,可以考虑复习*为什么使用 smolagents*部分以更深入理解。如果你表现良好,你已经准备好探索 smolagents 中更高级的主题了! ================================================ FILE: units/zh-CN/unit2/smolagents/quiz2.mdx ================================================ # 小测验(不计分)[[quiz2]] 现在该测试您对*代码智能体*、*工具调用智能体*和*工具*章节的理解了。本测验为可选且不计分。 --- ### Q1: 使用 `@tool` 装饰器创建工具与创建 `Tool` 的子类之间的主要区别是什么? 以下哪个陈述最能描述这两种定义工具方法的区别? @tool 装饰器是检索类工具的强制要求,而 Tool 的子类仅用于文本生成任务", explain: "两种方法都适用于任何类型的工具,包括检索类和文本生成类工具。", }, { text: "推荐使用 @tool 装饰器创建简单的基于函数的工具,而 Tool 的子类能为复杂功能或自定义元数据提供更大灵活性", explain: "正确。装饰器方法更简单,但子类化允许更定制化的行为。", correct: true }, { text: "@tool 只能用于多智能体系统,而创建 Tool 的子类适用于单智能体场景", explain: "所有智能体(单或多)都可以使用这两种方法定义工具,没有此类限制。", }, { text: "用 @tool 装饰函数可以替代文档字符串,而子类工具必须不包含文档字符串", explain: "两种方法都需要清晰的文档字符串。装饰器不会替代它们,子类仍然可以包含文档字符串。", } ]} /> --- ### Q2: CodeAgent 如何使用 ReAct(推理+行动)方法处理多步骤任务? 哪个陈述正确描述了 CodeAgent 执行系列步骤来解决任务的方式? --- ### Q3: 在 Hugging Face Hub 上共享工具的主要优势是什么? 选择开发者可能上传和共享自定义工具的最佳原因。 --- ### Q4: ToolCallingAgent 在执行操作方面与 CodeAgent 有何不同? 选择准确描述 ToolCallingAgent 工作方式的选项。 --- ### Q5: smolagents 默认工具箱包含哪些内容?为什么要使用它? 哪个陈述最能体现 smolagents 默认工具箱的目的和内容? --- 恭喜完成测验!🎉 如果有任何问题让您感到困难,请重新访问*代码智能体*、*工具调用智能体*或*工具*章节以加强理解。如果您表现出色,那么您已踏上构建强大 smolagents 应用的道路! ================================================ FILE: units/zh-CN/unit2/smolagents/retrieval_agents.mdx ================================================ # 构建智能驱动的 RAG 系统 > [!TIP] > 您可以通过 此 Notebook 跟随代码实践,该文件支持在 Google Colab 中运行。 检索增强生成(Retrieval-Augmented Generation,RAG)系统结合了数据检索和生成模型的能力,以提供上下文感知的响应。例如,用户的查询会被传递给搜索引擎,检索结果与查询一起提供给模型,模型随后根据查询和检索到的信息生成响应。 智能驱动的 RAG(Retrieval-Augmented Generation)通过**将自主智能体与动态知识检索相结合**,扩展了传统 RAG 系统。 传统 RAG 系统使用 LLM 根据检索数据回答查询,而智能驱动的 RAG **实现了对检索和生成流程的智能控制**,从而提高了效率和准确性。 传统 RAG 系统面临关键限制,例如**依赖单次检索步骤**,以及过度关注与用户查询的直接语义相似性,这可能会忽略相关信息。 智能驱动的 RAG 通过允许智能体自主制定搜索查询、评估检索结果并进行多次检索步骤,以生成更定制化和全面的输出,从而解决这些问题。 ## 基于 DuckDuckGo 的基础检索 让我们构建一个能够使用 DuckDuckGo 进行网页搜索的简单智能体。该智能体将检索信息并综合响应来回答查询。通过智能驱动的 RAG,Alfred 的智能体可以: * 搜索最新的超级英雄派对趋势 * 优化结果以包含奢侈元素 * 将信息综合成完整方案 以下是 Alfred 的智能体实现此功能的代码示例: ```python from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel # 初始化搜索工具 search_tool = DuckDuckGoSearchTool() # 初始化模型 model = InferenceClientModel() agent = CodeAgent( model=model, tools=[search_tool] ) # 使用示例 response = agent.run( "Search for luxury superhero-themed party ideas, including decorations, entertainment, and catering." ) print(response) ``` 智能体遵循以下流程: 1. **请求分析:** Alfred 的智能体识别查询的关键要素——重点关注装饰、娱乐和餐饮的豪华超级英雄主题派对规划 2. **执行检索:** 智能体利用 DuckDuckGo 搜索最新相关信息,确保符合 Alfred 对奢侈活动的精细要求 3. **信息综合:** 收集结果后,智能体将其处理为覆盖派对所有方面的可执行方案 4. **未来参考存储:** 智能体存储检索信息以便后续活动规划时快速访问,优化后续任务效率 ## 自定义知识库工具 对于专业任务,自定义知识库非常宝贵。让我们创建可以查询技术文档或专业知识的向量数据库工具。通过语义搜索,智能体可以找到与 Alfred 需求最相关的信息。 向量数据库(vector database)是通过专业 ML 模型实现丰富文档表示的集合,能够快速搜索和检索文档。 该方法将预定义知识与语义搜索相结合,为活动规划提供上下文感知解决方案。通过专业知识访问,Alfred 可以完善派对的每个细节。 在此示例中,我们将创建从自定义知识库检索派对策划创意的工具。使用 BM25 检索器搜索知识库并返回最佳结果,同时使用 `RecursiveCharacterTextSplitter` 将文档分割为更小的块以提高搜索效率: ```python from langchain.docstore.document import Document from langchain.text_splitter import RecursiveCharacterTextSplitter from smolagents import Tool from langchain_community.retrievers import BM25Retriever from smolagents import CodeAgent, InferenceClientModel class PartyPlanningRetrieverTool(Tool): name = "party_planning_retriever" description = "Uses semantic search to retrieve relevant party planning ideas for Alfred’s superhero-themed party at Wayne Manor." inputs = { "query": { "type": "string", "description": "The query to perform. This should be a query related to party planning or superhero themes.", } } output_type = "string" def __init__(self, docs, **kwargs): super().__init__(**kwargs) self.retriever = BM25Retriever.from_documents( docs, k=5 # 检索前 5 个文档 ) def forward(self, query: str) -> str: assert isinstance(query, str), "Your search query must be a string" docs = self.retriever.invoke( query, ) return "\nRetrieved ideas:\n" + "".join( [ f"\n\n===== Idea {str(i)} =====\n" + doc.page_content for i, doc in enumerate(docs) ] ) # 模拟派对策划知识库 party_ideas = [ {"text": "A superhero-themed masquerade ball with luxury decor, including gold accents and velvet curtains.", "source": "Party Ideas 1"}, {"text": "Hire a professional DJ who can play themed music for superheroes like Batman and Wonder Woman.", "source": "Entertainment Ideas"}, {"text": "For catering, serve dishes named after superheroes, like 'The Hulk's Green Smoothie' and 'Iron Man's Power Steak.'", "source": "Catering Ideas"}, {"text": "Decorate with iconic superhero logos and projections of Gotham and other superhero cities around the venue.", "source": "Decoration Ideas"}, {"text": "Interactive experiences with VR where guests can engage in superhero simulations or compete in themed games.", "source": "Entertainment Ideas"} ] source_docs = [ Document(page_content=doc["text"], metadata={"source": doc["source"]}) for doc in party_ideas ] # 分割文档以提高搜索效率 text_splitter = RecursiveCharacterTextSplitter( chunk_size=500, chunk_overlap=50, add_start_index=True, strip_whitespace=True, separators=["\n\n", "\n", ".", " ", ""], ) docs_processed = text_splitter.split_documents(source_docs) # 创建检索工具 party_planning_retriever = PartyPlanningRetrieverTool(docs_processed) # 初始化智能体 agent = CodeAgent(tools=[party_planning_retriever], model=InferenceClientModel()) # 使用示例 response = agent.run( "Find ideas for a luxury superhero-themed party, including entertainment, catering, and decoration options." ) print(response) ``` 增强后的智能体能够: 1. 首先检查文档中的相关信息 2. 结合知识库的洞察 3. 在内存中维护对话上下文 ## 增强的检索能力 构建智能驱动的 RAG 系统时,智能体可以采用以下高级策略: 1. **查询重构:** 智能体可以优化原始查询,生成更匹配目标文档的搜索词 2. **多步检索:** 智能体可以进行多次搜索,利用初步结果优化后续查询 3. **多源整合:** 结合来自网页搜索和本地文档等多个来源的信息 4. **结果验证:** 在将检索内容纳入响应前分析其相关性和准确性 有效的智能驱动 RAG 系统需要仔细考虑几个关键方面。智能体**应根据查询类型和上下文选择可用工具**,记忆系统帮助维护对话历史避免重复检索,后备策略确保在主要检索方法失败时系统仍能提供价值,验证步骤则帮助确保检索信息的准确性和相关性。 ## 资源 - [Agentic RAG: 使用查询重构和自查询加速您的 RAG 系统!🚀](https://huggingface.co/learn/cookbook/zh-CN/agent_rag) - 使用 smolagents 开发智能驱动 RAG 系统的实践指南 ================================================ FILE: units/zh-CN/unit2/smolagents/tool_calling_agents.mdx ================================================ # 将操作编写为代码片段或 JSON 结构 > [!TIP] > 您可以通过 此 Notebook 跟随代码实践,该文件支持在 Google Colab 中运行。 工具调用智能体(Tool Calling Agents)是 `smolagents` 中提供的第二种智能体类型。与使用 Python 代码片段的代码智能体(Code Agents)不同,这类智能体**利用 LLM 提供商的内置工具调用能力**来生成 **JSON 结构**的工具调用指令。这是 OpenAI、Anthropic 等主流提供商采用的标准方法。 当 Alfred 想要搜索餐饮服务和派对创意时,`CodeAgent` 会生成并运行如下 Python 代码: ```python for query in [ "Best catering services in Gotham City", "Party theme ideas for superheroes" ]: print(web_search(f"Search for: {query}")) ``` 而 `ToolCallingAgent` 则会创建 JSON 结构: ```python [ {"name": "web_search", "arguments": "Best catering services in Gotham City"}, {"name": "web_search", "arguments": "Party theme ideas for superheroes"} ] ``` 该 JSON 结构随后会被用于执行工具调用。 尽管 `smolagents` 主要专注于 `CodeAgents`(因为[它们整体表现更好](https://huggingface.co/papers/2402.01030)),但对于不需要变量处理或复杂工具调用的简单系统,`ToolCallingAgents` 仍然可以高效工作。 ![代码操作与 JSON 操作对比](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/code_vs_json_actions.png) ## 工具调用智能体的工作原理 工具调用智能体遵循与代码智能体相同的多步骤工作流程(详见[前一章节](./code_agents))。关键区别在于**操作结构方式**:智能体不再生成可执行代码,而是**生成指定工具名称和参数的 JSON 对象**,系统随后**解析这些指令**来执行相应工具。 ## 示例:运行工具调用智能体 让我们重新审视 Alfred 开始筹备派对的示例,这次使用 `ToolCallingAgent` 来展示区别。我们将构建一个能够使用 DuckDuckGo 进行网页搜索的智能体,与代码智能体示例的唯一区别在于智能体类型——框架会处理其他所有细节: ```python from smolagents import ToolCallingAgent, DuckDuckGoSearchTool, InferenceClientModel agent = ToolCallingAgent(tools=[DuckDuckGoSearchTool()], model=InferenceClientModel()) agent.run("Search for the best music recommendations for a party at the Wayne's mansion.") ``` 当查看智能体的执行跟踪时,您将看到类似以下内容而非 `Executing parsed code:`: ```text ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ Calling tool: 'web_search' with arguments: {'query': "best music recommendations for a party at Wayne's │ │ mansion"} │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ``` 智能体生成结构化的工具调用指令,系统通过处理这些指令来生成输出,而非像 `CodeAgent` 那样直接执行代码。 现在我们已经了解两种智能体类型,可以根据需求选择合适的一种。让我们继续探索 `smolagents`,让 Alfred 的派对大获成功!🎉 ## 资源 - [ToolCallingAgent 文档](https://huggingface.co/docs/smolagents/v1.8.1/en/reference/agents#smolagents.ToolCallingAgent) - ToolCallingAgent 的官方文档 ================================================ FILE: units/zh-CN/unit2/smolagents/tools.mdx ================================================ # 工具 正如我们在[第一单元](https://huggingface.co/learn/agents-course/unit1/tools)所探讨的,智能体通过工具执行各类操作。在`smolagents`框架中,工具被视为 **LLM 可以在智能体系统中调用的函数**。 要使LLM能够调用工具,需要为其提供包含以下关键要素的**接口描述**: - **名称**:工具的标识名称 - **工具描述**:工具的功能说明 - **输入类型及描述**:工具接受的参数说明 - **输出类型**:工具的返回结果类型 以韦恩庄园筹备派对为例,Alfred 需要多种工具来收集信息——从搜索餐饮服务到寻找派对主题创意。以下是一个简单搜索工具的接口示例: - **名称:** `web_search` - **工具描述:** 根据特定查询进行网络搜索 - **输入:** `query` (字符串) - 需要查找的搜索关键词 - **输出:** 包含搜索结果的字符串 通过使用这些工具,Alfred 能够做出明智决策并收集派对筹备所需的所有信息。 下方动画展示了工具调用的管理流程: ![来自 https://huggingface.co/docs/smolagents/conceptual_guides/react 的智能体流程](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/Agent_ManimCE.gif) ## 工具创建方法 在`smolagents`中,可以通过两种方式定义工具: 1. **使用`@tool`装饰器**创建基于函数的简单工具 2. **创建`Tool`的子类**实现复杂功能 ### `@tool`装饰器 `@tool`装饰器是**定义简单工具的推荐方式**。在底层,smolagents 会从 Python 函数解析基本信息。因此,清晰的函数命名和规范的文档字符串(docstring)能让 LLM 更易理解工具用途。 使用此方法时,我们需要定义包含以下要素的函数: - **明确描述性的函数名称**:帮助LLM理解其用途 - **输入输出的类型提示**:确保正确使用 - **详细描述**:包含明确描述各参数的`Args:`部分,这些描述为 LLM 提供关键上下文信息 #### 创建餐饮评分查询工具 Alfred Catering > [!TIP] > 您可以通过 此 Notebook 跟随代码实践,该文件支持在 Google Colab 中运行。 假设 Alfred 已确定派对菜单,但需要为大量宾客准备食物。为此,他希望雇佣餐饮服务并需要找到当地评分最高的选择。 以下是通过`@tool`装饰器实现该功能的示例: ```python from smolagents import CodeAgent, InferenceClientModel, tool # 假设我们有一个获取最高评分餐饮服务的函数 @tool def catering_service_tool(query: str) -> str: """ This tool returns the highest-rated catering service in Gotham City. Args: query: A search term for finding catering services. """ # 示例餐饮服务及评分列表 services = { "Gotham Catering Co.": 4.9, "Wayne Manor Catering": 4.8, "Gotham City Events": 4.7, } # 查找评分最高的餐饮服务(模拟搜索查询过滤) best_service = max(services, key=services.get) return best_service agent = CodeAgent(tools=[catering_service_tool], model=InferenceClientModel()) # 运行智能体寻找最佳餐饮服务 result = agent.run( "Can you give me the name of the highest-rated catering service in Gotham City?" ) print(result) # Output: Gotham Catering Co. ``` ### 通过Python类定义工具 此方法需要创建[`Tool`](https://huggingface.co/docs/smolagents/v1.8.1/en/reference/tools#smolagents.Tool)的子类。对于复杂工具,我们可以通过类封装函数及其元数据来帮助 LLM 理解使用方式。在类中需要定义: - `name`: 工具名称 - `description`: 用于构建智能体系统提示的描述 - `inputs`: 包含`type`和`description`的字典,帮助Python解释器处理输入 - `output_type`: 指定期望的输出类型 - `forward`: 包含执行逻辑的方法 以下是通过`Tool`类构建工具并与`CodeAgent`集成的示例: #### 创建超级英雄主题派对创意生成工具 Alfred 计划在庄园举办**超级英雄主题派对**,但需要独特创意让活动与众不同。作为完美管家,他希望用新颖主题给宾客带来惊喜。 为此,我们可以创建根据类别生成派对创意的工具,帮助 Alfred 找到最惊艳的主题方案: ```python from smolagents import Tool, CodeAgent, InferenceClientModel class SuperheroPartyThemeTool(Tool): name = "superhero_party_theme_generator" description = """ This tool suggests creative superhero-themed party ideas based on a category. It returns a unique party theme idea.""" inputs = { "category": { "type": "string", "description": "The type of superhero party (e.g., 'classic heroes', 'villain masquerade', 'futuristic Gotham').", } } output_type = "string" def forward(self, category: str): themes = { "classic heroes": "Justice League Gala: Guests come dressed as their favorite DC heroes with themed cocktails like 'The Kryptonite Punch'.", "villain masquerade": "Gotham Rogues' Ball: A mysterious masquerade where guests dress as classic Batman villains.", "futuristic Gotham": "Neo-Gotham Night: A cyberpunk-style party inspired by Batman Beyond, with neon decorations and futuristic gadgets." } return themes.get(category.lower(), "Themed party idea not found. Try 'classic heroes', 'villain masquerade', or 'futuristic Gotham'.") # 实例化工具 party_theme_tool = SuperheroPartyThemeTool() agent = CodeAgent(tools=[party_theme_tool], model=InferenceClientModel()) # 运行智能体生成派对主题 result = agent.run( "What would be a good superhero party idea for a 'villain masquerade' theme?" ) print(result) # Output: "Gotham Rogues' Ball: A mysterious masquerade where guests dress as classic Batman villains." ``` 借助此工具,Alfred 将成为终极超级管家,为宾客呈现难忘的超级英雄主题派对!🦸♂️🦸♀️ ## 默认工具箱 `smolagents` 自带一组预构建工具,可直接注入到您的智能体中。[默认工具箱](https://huggingface.co/docs/smolagents/guided_tour?build-a-tool=Decorate+a+function+with+%40tool#default-toolbox) 包含: - **PythonInterpreterTool** - **FinalAnswerTool** - **UserInputTool** - **DuckDuckGoSearchTool** - **GoogleSearchTool** - **VisitWebpageTool** Alfred 可以使用多种工具来确保韦恩庄园的完美派对: - 首先,他可以使用 `DuckDuckGoSearchTool` 搜索创意超级英雄主题派对灵感 - 对于餐饮,他依赖 `GoogleSearchTool` 查找哥谭市评分最高的服务 - 要管理座位安排,Alfred 可以通过 `PythonInterpreterTool` 运行计算 - 收集完所有信息后,他使用 `FinalAnswerTool` 整合计划 通过这些工具,Alfred 确保派对既出众又顺利。🦇💡 ## 共享与导入工具 **smolagents** 最强大的功能之一是能够将自定义工具共享到 Hub 并无缝集成社区创建的工具。这包括与 **HF Spaces** 和 **LangChain 工具**的连接,显著增强了 Alfred 策划难忘韦恩庄园派对的能力。🎭 通过这些集成,Alfred 可以利用高级活动策划工具——无论是调整灯光营造完美氛围、为派对策划理想歌单,还是与哥谭市最优秀的餐饮服务商协调。 以下是展示这些功能如何提升派对体验的示例: ### 向 Hub 共享工具 与社区分享自定义工具非常简单!只需使用 `push_to_hub()` 方法将其上传到您的 Hugging Face 账户。 例如,Alfred 可以分享他的 `party_theme_tool` 以帮助其他人找到哥谭市最好的餐饮服务。具体操作如下: ```python party_theme_tool.push_to_hub("{your_username}/party_theme_tool", token="") ``` ### 从 Hub 导入工具 您可以使用 `load_tool()` 函数轻松导入其他用户创建的工具。例如,Alfred 可能希望使用 AI 生成派对的宣传图片。无需从头构建工具,他可以直接使用社区预定义的方案: ```python from smolagents import load_tool, CodeAgent, InferenceClientModel image_generation_tool = load_tool( "m-ric/text-to-image", trust_remote_code=True ) agent = CodeAgent( tools=[image_generation_tool], model=InferenceClientModel() ) agent.run("Generate an image of a luxurious superhero-themed party at Wayne Manor with made-up superheros.") ``` ### 将 Hugging Face Space 导入为工具 您可以使用 `Tool.from_space()` 将 HF Space 作为工具导入。这开启了与社区数千个 Space 集成的可能性,从图像生成到数据分析均可实现。 工具将通过 `gradio_client` 连接 Space 的后端,请确保已通过 `pip` 安装该依赖(如果尚未安装)。 对于本次派对,Alfred 可以使用现有的 HF Space 生成公告所需的 AI 图像(替代之前提到的预建工具)。让我们开始构建: ```python from smolagents import CodeAgent, InferenceClientModel, Tool image_generation_tool = Tool.from_space( "black-forest-labs/FLUX.1-schnell", name="image_generator", description="Generate an image from a prompt" ) model = InferenceClientModel("Qwen/Qwen2.5-Coder-32B-Instruct") agent = CodeAgent(tools=[image_generation_tool], model=model) agent.run( "Improve this prompt, then generate an image of it.", additional_args={'user_prompt': 'A grand superhero-themed party at Wayne Manor, with Alfred overseeing a luxurious gala'} ) ``` ### 导入 LangChain 工具 我们将在后续章节讨论 `LangChain` 框架。目前需要注意的是,您可以在 smolagents 工作流中复用 LangChain 工具! 您可以使用 `Tool.from_langchain()` 方法轻松加载 LangChain 工具。 追求完美的 Alfred 正在筹备一场盛大的超级英雄之夜活动(趁韦恩一家外出时),为确保每个细节都超出预期,他借助 LangChain 工具来寻找顶级的娱乐创意。 具体实现如下: ```python from langchain.agents import load_tools from smolagents import CodeAgent, InferenceClientModel, Tool search_tool = Tool.from_langchain(load_tools(["serpapi"])[0]) agent = CodeAgent(tools=[search_tool], model=model) agent.run("Search for luxury entertainment ideas for a superhero-themed event, such as live performances and interactive experiences.") ``` 通过此设置,Alfred 能快速发现高端娱乐选项,确保哥谭的精英宾客获得难忘体验。该工具帮助他策划韦恩庄园的完美超级英雄主题活动!🎉 ## 资源 - [工具教程](https://huggingface.co/docs/smolagents/tutorials/tools) - 通过本教程学习如何高效使用工具 - [工具文档](https://huggingface.co/docs/smolagents/v1.8.1/en/reference/tools) - 全面的工具参考文档 - [工具使用导览](https://huggingface.co/docs/smolagents/v1.8.1/en/guided_tour#tools) - 逐步指导如何构建和使用工具 - [构建高效智能体](https://huggingface.co/docs/smolagents/tutorials/building_good_agents) - 关于开发可靠高性能自定义函数智能体的最佳实践指南 ================================================ FILE: units/zh-CN/unit2/smolagents/vision_agents.mdx ================================================ # 使用 smolagents 构建视觉智能体 > [!WARNING] > 本节示例需要接入强大的视觉语言模型(VLM)。我们使用 GPT-4o API 进行了测试。 > 若需了解 smolagents 和 Hugging Face 支持的其他替代方案,请参考为什么选择smolagents章节。 赋予智能体视觉能力对于超越文本处理的任务至关重要。网页浏览、文档理解等现实场景都需要解析丰富的视觉内容。smolagents 内置支持视觉语言模型(VLMs),使智能体能够有效处理图像信息。 假设韦恩庄园的管家 Alfred 需要核验派对嘉宾身份。考虑到他可能无法识别所有来宾,我们可以构建基于 VLM 的智能体,通过视觉信息检索来辅助身份验证决策。以下是具体实现: ## 初始执行阶段提供图像 > [!TIP] > 配套代码可在Google Colab 笔记本中查看。 该方法在智能体启动时通过 task_images 参数传入图像,智能体在执行过程中持续处理这些图像。 假设 Alfred 需要核验超级英雄身份,他已有历史派对嘉宾图像数据库。 当新访客到来时,智能体可通过图像比对进行准入决策。 当前场景中,Alfred 怀疑访客可能是小丑假扮的神奇女侠。我们需要构建身份验证系统: ```python from PIL import Image import requests from io import BytesIO image_urls = [ "https://upload.wikimedia.org/wikipedia/commons/e/e8/The_Joker_at_Wax_Museum_Plus.jpg", # 小丑图像 "https://upload.wikimedia.org/wikipedia/en/9/98/Joker_%28DC_Comics_character%29.jpg" # 小丑图像 ] images = [] for url in image_urls: headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" } response = requests.get(url,headers=headers) image = Image.open(BytesIO(response.content)).convert("RGB") images.append(image) ``` 完成图像加载后,智能体将判断访客身份:究竟是超级英雄(Wonder Woman)还是反派角色(The Joker)。 ```python from smolagents import CodeAgent, OpenAIServerModel model = OpenAIServerModel(model_id="gpt-4o") # 实例化智能体 agent = CodeAgent( tools=[], model=model, max_steps=20, verbosity_level=2 ) response = agent.run( """ Describe the costume and makeup that the comic character in these photos is wearing and return the description. Tell me if the guest is The Joker or Wonder Woman. """, images=images ) ``` 以下是我的运行结果(实际输出可能因环境差异有所不同,正如前文所述): ```python { 'Costume and Makeup - First Image': ( 'Purple coat and a purple silk-like cravat or tie over a mustard-yellow shirt.', 'White face paint with exaggerated features, dark eyebrows, blue eye makeup, red lips forming a wide smile.' ), 'Costume and Makeup - Second Image': ( 'Dark suit with a flower on the lapel, holding a playing card.', 'Pale skin, green hair, very red lips with an exaggerated grin.' ), 'Character Identity': 'This character resembles known depictions of The Joker from comic book media.' } ``` 在这种情况下,输出结果揭示了这个人正在冒充他人,因此我们可以阻止 The Joker 进入派对! ## 提供动态检索图像 > [!TIP] > 您可以在 这个 Python 文件 中查看代码。 前面的方法具有很高的价值,并且有许多潜在的应用场景。然而,在客人不在数据库中的情况下,我们需要探索其他识别方式。一种可能的解决方案是从外部来源动态检索图像和信息,例如通过浏览网页获取详细信息。 在此方法中,图像是在执行过程中动态添加到智能体的记忆中的。我们知道,`smolagents` 中的智能体基于 `MultiStepAgent` 类,该类是 ReAct 框架的抽象。此类以结构化的周期运行,在不同阶段记录各种变量和知识: 1. **SystemPromptStep:** 存储系统提示。 2. **TaskStep:** 记录用户查询和提供的任何输入。 3. **ActionStep:** 捕获智能体操作和结果的日志。 这种结构化的方法使智能体能够动态地结合视觉信息,并对不断变化的任务做出适应性响应。以下是已经见过的图表,展示了动态工作流程过程以及不同步骤如何在智能体生命周期内集成。在浏览时,智能体可以截取屏幕截图并将其保存为 `ActionStep` 中的 `observation_images`。 ![Dynamic image retrieval](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/smolagents-can-see/diagram_adding_vlms_smolagents.png) 现在我们理解了需求,让我们构建完整的示例。在这种情况下,Alfred 希望完全控制访客验证过程,因此浏览详情成为可行的解决方案。为了完成这个示例,我们需要为智能体提供一组新的工具。此外,我们将使用 Selenium 和 Helium,这些是浏览器自动化工具。这将使我们能够构建一个探索网络、搜索潜在访客详情并检索验证信息的智能体。让我们安装所需的工具: ```bash pip install "smolagents[all]" helium selenium python-dotenv ``` 我们需要一组专为浏览设计的智能体工具,例如“search_item_ctrl_f”、“go_back”和“close_popups”。这些工具允许智能体像浏览网页的人一样行事。 ```python @tool def search_item_ctrl_f(text: str, nth_result: int = 1) -> str: """ Searches for text on the current page via Ctrl + F and jumps to the nth occurrence. Args: text: The text to search for nth_result: Which occurrence to jump to (default: 1) """ elements = driver.find_elements(By.XPATH, f"//*[contains(text(), '{text}')]") if nth_result > len(elements): raise Exception(f"Match n°{nth_result} not found (only {len(elements)} matches found)") result = f"Found {len(elements)} matches for '{text}'." elem = elements[nth_result - 1] driver.execute_script("arguments[0].scrollIntoView(true);", elem) result += f"Focused on element {nth_result} of {len(elements)}" return result @tool def go_back() -> None: """Goes back to previous page.""" driver.back() @tool def close_popups() -> str: """ Closes any visible modal or pop-up on the page. Use this to dismiss pop-up windows! This does not work on cookie consent banners. """ webdriver.ActionChains(driver).send_keys(Keys.ESCAPE).perform() ``` 我们还需要保存屏幕截图的功能,因为这是我们的 VLM 智能体完成任务时必不可少的一部分。此功能会捕获屏幕截图并将其保存在 `step_log.observations_images = [image.copy()]` 中,从而允许智能体在导航时动态存储和处理图像。 ```python def save_screenshot(step_log: ActionStep, agent: CodeAgent) -> None: sleep(1.0) # 让 JavaScript 动画在截图之前完成 driver = helium.get_driver() current_step = step_log.step_number if driver is not None: for step_logs in agent.logs: # 从日志中删除先前的截图以进行精简处理 if isinstance(step_log, ActionStep) and step_log.step_number <= current_step - 2: step_logs.observations_images = None png_bytes = driver.get_screenshot_as_png() image = Image.open(BytesIO(png_bytes)) print(f"Captured a browser screenshot: {image.size} pixels") step_log.observations_images = [image.copy()] # 创建副本以确保其持久保存,重要!! # 使用当前 URL 更新观察结果 url_info = f"Current url: {driver.current_url}" step_log.observations = url_info if step_logs.observations is None else step_log.observations + "\n" + url_info return ``` 此函数作为 `step_callback` 传递给智能体,因为它在智能体执行的每一步结束时被触发。这使得智能体能够在整个过程中动态捕获和存储屏幕截图。 现在,我们可以生成用于浏览网页的视觉智能体,为其提供我们创建的工具,以及 `DuckDuckGoSearchTool` 以探索网页。此工具将帮助智能体根据视觉线索检索验证访客身份所需的信息。 ```python from smolagents import CodeAgent, OpenAIServerModel, DuckDuckGoSearchTool model = OpenAIServerModel(model_id="gpt-4o") agent = CodeAgent( tools=[DuckDuckGoSearchTool(), go_back, close_popups, search_item_ctrl_f], model=model, additional_authorized_imports=["helium"], step_callbacks=[save_screenshot], max_steps=20, verbosity_level=2, ) ``` 有了这些,Alfred 准备检查访客的身份,并根据这些信息做出是否允许他们进入派对的明智决定: ```python agent.run(""" I am Alfred, the butler of Wayne Manor, responsible for verifying the identity of guests at party. A superhero has arrived at the entrance claiming to be Wonder Woman, but I need to confirm if she is who she says she is. Please search for images of Wonder Woman and generate a detailed visual description based on those images. Additionally, navigate to Wikipedia to gather key details about her appearance. With this information, I can determine whether to grant her access to the event. """ + helium_instructions) ``` 您可以看到,我们将 `helium_instructions` 作为任务的一部分包含在内。这个特殊的提示旨在控制智能体的导航,确保它在浏览网页时遵循正确的步骤。 让我们看看这在下面的视频中是如何工作的: 这是最终输出: ```python Final answer: Wonder Woman is typically depicted wearing a red and gold bustier, blue shorts or skirt with white stars, a golden tiara, silver bracelets, and a golden Lasso of Truth. She is Princess Diana of Themyscira, known as Diana Prince in the world of men. ``` 通过这些步骤,我们成功地为派对创建了一个身份验证系统! Alfred 现在拥有必要的工具,可以确保只有正确的宾客能够进入庄园。一切准备就绪,可以享受在韦恩庄园的美好时光! ## 进一步阅读 - [我们让 smolagents 有了视觉能力](https://huggingface.co/blog/smolagents-can-see) - 博客文章描述了视觉智能体的功能。 - [使用智能体进行网页浏览 🤖🌐](https://huggingface.co/docs/smolagents/examples/web_browser) - 使用视觉智能体进行网页浏览的示例。 - [网页浏览视觉智能体示例](https://github.com/huggingface/smolagents/blob/main/src/smolagents/vision_web_browser.py) - 使用视觉智能体进行网页浏览的示例。 ================================================ FILE: units/zh-CN/unit2/smolagents/why_use_smolagents.mdx ================================================ ![smolagents 标志](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/smolagents/license_to_call.png) # 为什么选择 smolagents 在本模块中,我们将探讨使用 [smolagents](https://huggingface.co/docs/smolagents/en/index) 的优缺点,帮助您做出明智的决策,判断它是否是满足您需求的正确框架。 ## 什么是 `smolagents`? `smolagents` 是一个简单而强大的框架,用于构建 AI 智能体。它为 LLM 提供了与现实世界互动的能力,例如搜索或生成图像。 正如我们在第 1 单元中学到的,AI 智能体是使用 LLM 基于 **'观察'** 生成 **'思考'** 并执行 **'操作'** 的程序。接下来我们来探讨这在 smolagents 中是如何实现的。 ### `smolagents` 的关键优势 - **简洁性:** 最小的代码复杂性和抽象层,使框架易于理解、采用和扩展。 - **灵活的 LLM 支持:** 通过与 Hugging Face 工具和外部 API 的集成,支持任何 LLM。 - **代码优先方法:** 首选支持直接在代码中编写操作的 Code Agents,无需解析并简化工具调用。 - **HF Hub 集成:** 与 Hugging Face Hub 无缝集成,允许使用 Gradio Spaces 作为工具。 ### 何时使用 smolagents? 考虑到这些优势,我们应该在什么情况下选择 smolagents 而不是其他框架? smolagents 在以下情况下是最理想的: - 您需要一个 **轻量级且最小化的解决方案**。 - 您希望 **快速实验** 而无需复杂的配置。 - 您的应用逻辑 **相对简单**。 ### 代码 vs. JSON 操作 与其他框架中的智能体以 JSON 形式编写操作不同,`smolagents` **专注于代码中的工具调用**,简化了执行过程。这是因为无需解析 JSON 来构建调用工具的代码:输出可以直接执行。 下图展示了这种差异: ![代码 vs. JSON 操作](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/code_vs_json_actions.png) 要回顾代码与 JSON 操作之间的区别,您可以重新访问 [第 1 单元的操作部分](https://huggingface.co/learn/agents-course/unit1/actions#actions-enabling-the-agent-to-engage-with-its-environment)。 ### `smolagents` 中的智能体类型 `smolagents` 中的智能体作为 **多步骤智能体** 运行。 每个 [`MultiStepAgent`](https://huggingface.co/docs/smolagents/main/en/reference/agents#smolagents.MultiStepAgent) 执行: - 一次思考 - 一次工具调用和执行 除了使用 **[CodeAgent](https://huggingface.co/docs/smolagents/main/en/reference/agents#smolagents.CodeAgent)** 作为主要类型的智能体外,smolagents 还支持 **[ToolCallingAgent](https://huggingface.co/docs/smolagents/main/en/reference/agents#smolagents.ToolCallingAgent)**,后者以 JSON 形式编写工具调用。 我们将在接下来的部分中更详细地探讨每种智能体类型。 > [!TIP] > 在 smolagents 中,工具是使用 @tool 装饰器包装 Python 函数或 Tool 类定义的。 ### `smolagents` 中的模型集成 `smolagents` 支持灵活的 LLM 集成,允许使用符合 [某些标准](https://huggingface.co/docs/smolagents/main/en/reference/models) 的任何可调用模型。该框架提供了多个预定义类以简化模型连接: - **[TransformersModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.TransformersModel):** 实现本地 `transformers` 管道以实现无缝集成。 - **[InferenceClientModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.InferenceClientModel):** 通过 [Hugging Face 的基础设施](https://huggingface.co/docs/api-inference/index) 或越来越多的 [第三方推理提供商](https://huggingface.co/docs/huggingface_hub/main/en/guides/inference#supported-providers-and-tasks) 支持 [无服务器推理](https://huggingface.co/docs/huggingface_hub/main/en/guides/inference) 调用。 - **[LiteLLMModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.LiteLLMModel):** 利用 [LiteLLM](https://www.litellm.ai/) 实现轻量级模型交互。 - **[OpenAIServerModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.OpenAIServerModel):** 连接到提供 OpenAI API 接口的任何服务。 - **[AzureOpenAIServerModel](https://huggingface.co/docs/smolagents/main/en/reference/models#smolagents.AzureOpenAIServerModel):** 支持与任何 Azure OpenAI 部署集成。 这种灵活性确保开发人员可以选择最适合其特定用例的模型和服务,并允许轻松进行实验。 现在我们已经了解了何时以及为何使用 smolagents,让我们深入探讨这个强大的库吧! ## 资源 - [smolagents 博客](https://huggingface.co/blog/smolagents) - 关于 smolagents 和代码交互的介绍 ================================================ FILE: units/zh-CN/unit3/README.md ================================================ ================================================ FILE: units/zh-CN/unit3/agentic-rag/agent.mdx ================================================ # 创建你的 Gala 智能体 现在我们已经为 Alfred 构建了所有必要组件,是时候将它们整合成一个完整的智能体来协助举办我们的奢华盛会了。 在本节中,我们将把宾客信息检索、网络搜索、天气信息和 Hub 统计工具整合成一个强大的智能体。 ## 组装 Alfred:完整智能体 我们不需要重新实现之前章节创建的所有工具,只需从保存的tools.py和retriever.py模块中导入它们即可。 > [!TIP] > 如果你尚未实现这些工具,请返回工具检索器章节进行实现,并将它们添加到`tools.py`和`retriever.py`文件中。 让我们从之前章节导入必要的库和工具: ```python # 导入必要的库 import random from smolagents import CodeAgent, InferenceClientModel # 从自定义模块导入工具 from tools import DuckDuckGoSearchTool, WeatherInfoTool, HubStatsTool from retriever import load_guest_dataset ``` 现在让我们将所有工具组合成一个智能体: ```python # 初始化 Hugging Face 模型 model = InferenceClientModel() # 初始化网络搜索工具 search_tool = DuckDuckGoSearchTool() # 初始化天气工具 weather_info_tool = WeatherInfoTool() # 初始化 Hub 统计工具 hub_stats_tool = HubStatsTool() # 加载宾客数据集并初始化宾客信息工具 guest_info_tool = load_guest_dataset() # 创建包含所有工具的 Alfred alfred = CodeAgent( tools=[guest_info_tool, weather_info_tool, hub_stats_tool, search_tool], model=model, add_base_tools=True, # 添加额外的基础工具 planning_interval=3 # 每 3 步启用规划 ) ``` ```python # 导入必要库 from llama_index.core.agent.workflow import AgentWorkflow from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI from tools import search_tool, weather_info_tool, hub_stats_tool from retriever import guest_info_tool ``` Now, let's combine all these tools into a single agent: ```python # 初始化 Hugging Face 模型 llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") # 创建包含所有工具的 Alfred alfred = AgentWorkflow.from_tools_or_functions( [guest_info_tool, search_tool, weather_info_tool, hub_stats_tool], llm=llm, ) ``` ```python from typing import TypedDict, Annotated from langgraph.graph.message import add_messages from langchain_core.messages import AnyMessage, HumanMessage, AIMessage from langgraph.prebuilt import ToolNode from langgraph.graph import START, StateGraph from langgraph.prebuilt import tools_condition from langchain_huggingface import HuggingFaceEndpoint, ChatHuggingFace from tools import DuckDuckGoSearchRun, weather_info_tool, hub_stats_tool from retriever import guest_info_tool ``` 现在将所有工具整合到单一智能体: ```python # 初始化网络搜索工具 search_tool = DuckDuckGoSearchRun() # 生成包含工具的聊天接口 llm = HuggingFaceEndpoint( repo_id="Qwen/Qwen2.5-Coder-32B-Instruct", huggingfacehub_api_token=HUGGINGFACEHUB_API_TOKEN, ) chat = ChatHuggingFace(llm=llm, verbose=True) tools = [guest_info_tool, search_tool, weather_info_tool, hub_stats_tool] chat_with_tools = chat.bind_tools(tools) # 生成 AgentState 和 Agent 图 class AgentState(TypedDict): messages: Annotated[list[AnyMessage], add_messages] def assistant(state: AgentState): return { "messages": [chat_with_tools.invoke(state["messages"])], } ## 构建流程图 builder = StateGraph(AgentState) # 定义节点:执行具体工作 builder.add_node("assistant", assistant) builder.add_node("tools", ToolNode(tools)) # 定义边:控制流程走向 builder.add_edge(START, "assistant") builder.add_conditional_edges( "assistant", # 如果最新消息需要工具调用,则路由到 tools 节点 # 否则直接响应 tools_condition, ) builder.add_edge("tools", "assistant") alfred = builder.compile() ``` 您的智能体现已准备就绪! ## 使用 Alfred:端到端示例 现在 Alfred 已配备所有必要工具,让我们看看他如何协助处理晚会中的各种任务。 ### 示例 1:查找嘉宾信息 展示 Alfred 如何协助获取嘉宾信息: ```python query = "Tell me about 'Lady Ada Lovelace'" response = alfred.run(query) print("🎩 Alfred's Response:") print(response) ``` 预期输出: ``` 🎩 Alfred's Response: 根据检索到的信息,Ada Lovelace 女士是位备受尊敬的数学家兼好友。她因在数学和计算领域的开创性工作而闻名,常因其在 Charles Babbage 分析机方面的工作被誉为第一位计算机程序员。她的电子邮箱是 ada.lovelace@example.com。 ``` ```python query = "Tell me about Lady Ada Lovelace. What's her background?" response = await alfred.run(query) print("🎩 Alfred's Response:") print(response.response.blocks[0].text) ``` 预期输出: ``` 🎩 Alfred's Response: Ada Lovelace 女士是英国数学家和作家,以她在 Charles Babbage 分析机方面的工作闻名。她是第一个认识到该机器具有纯计算之外应用潜力的人。 ``` ```python response = alfred.invoke({"messages": "Tell me about 'Lady Ada Lovelace'"}) print("🎩 Alfred's Response:") print(response['messages'][-1].content) ``` 预期输出: ``` 🎩 Alfred's Response: Ada Lovelace,全名 Augusta Ada King,洛夫莱斯伯爵夫人,是英国数学家和作家。出生于 1815 年 12 月 10 日,逝世于 1852 年 11 月 27 日,她因在 Charles Babbage 提出的机械通用计算机分析机方面的工作而闻名。Ada Lovelace 被誉为第一位计算机程序员,因为她于 1843 年为分析机创建了程序。她认识到该机器的用途不仅限于计算,这种远见在当时极为罕见。她对计算机科学领域的贡献为未来发展奠定了基础。每年十月设立的 Ada Lovelace 日正是为了纪念她在科技领域的开创性工作,激励女性在 STEM 领域的发展。 ``` ### 示例 2:烟花天气核查 展示 Alfred 如何协助天气查询: ```python query = "What's the weather like in Paris tonight? Will it be suitable for our fireworks display?" response = alfred.run(query) print("🎩 Alfred's Response:") print(response) ``` 预期输出(存在随机性差异): ``` 🎩 Alfred's Response: 已为您查询巴黎天气。当前天气晴朗,气温 25°C。这样的条件非常适合今晚的烟花表演。晴朗的夜空将为壮观表演提供绝佳能见度,舒适的温度也能确保宾客们愉快享受户外活动。 ``` ```python query = "What's the weather like in Paris tonight? Will it be suitable for our fireworks display?" response = await alfred.run(query) print("🎩 Alfred's Response:") print(response) ``` 预期输出: ``` 🎩 Alfred's Response: 巴黎今夜有雨,气温 15°C。考虑到降雨情况,可能不适宜进行烟花表演。 ``` ```python response = alfred.invoke({"messages": "What's the weather like in Paris tonight? Will it be suitable for our fireworks display?"}) print("🎩 Alfred's Response:") print(response['messages'][-1].content) ``` 预期输出: ``` 🎩 Alfred's Response: 巴黎今夜有雨且气温 15°C,可能不适宜您的烟花表演计划。 ``` ### 示例 3:给 AI 研究者留下深刻印象 展示 Alfred 如何协助与 AI 研究者互动: ```python query = "One of our guests is from Qwen. What can you tell me about their most popular model?" response = alfred.run(query) print("🎩 Alfred's Response:") print(response) ``` 预期输出: ``` 🎩 Alfred's Response: Qwen 最受欢迎的模型是 Qwen/Qwen2.5-VL-7B-Instruct,下载量达 3,313,345 次。 ``` ```python query = "One of our guests is from Google. What can you tell me about their most popular model?" response = await alfred.run(query) print("🎩 Alfred's Response:") print(response) ``` 预期输出: ``` 🎩 Alfred's Response: Hugging Face Hub 上 Google 最受欢迎的模型是 google/electra-base-discriminator,下载量达 28,546,752 次。 ``` ```python response = alfred.invoke({"messages": "One of our guests is from Qwen. What can you tell me about their most popular model?"}) print("🎩 Alfred's Response:") print(response['messages'][-1].content) ``` 预期输出: ``` 🎩 Alfred's Response: Qwen 下载量最高的模型是 Qwen/Qwen2.5-VL-7B-Instruct,下载量达 3,313,345 次。 ``` ### 示例 4:组合多工具应用 展示 Alfred 如何协助准备与 Nikola Tesla 博士的对话: ```python query = "I need to speak with Dr. Nikola Tesla about recent advancements in wireless energy. Can you help me prepare for this conversation?" response = alfred.run(query) print("🎩 Alfred's Response:") print(response) ``` 预期输出: ``` 🎩 Alfred's Response: 我已收集信息帮助您准备与 Nikola Tesla 博士的对话。 嘉宾信息: 姓名:Dr. Nikola Tesla 关系:大学时期的老友 描述:他是您大学时期的老友,最近刚获得新型无线能量传输系统的专利,非常乐意与您讨论。请记住他对鸽子情有独钟,这可能是很好的闲聊话题。 邮箱:nikola.tesla@gmail.com 无线能源最新进展: 根据网络搜索,以下是无线能量传输领域的最新发展: 1. 研究人员在使用聚焦电磁波进行远距离无线输电方面取得进展 2. 多家公司正在开发用于消费电子的谐振感应耦合技术 3. 无物理连接的电动汽车充电新应用 对话切入点: 1. "我很想听听您关于无线能量传输新专利的情况,与大学时期的原始概念相比有何改进?" 2. "您是否关注近期消费电子谐振感应耦合技术的发展?对他们的方法有何看法?" 3. "您的鸽子最近好吗?我记得您对它们特别着迷" 这些内容将为您与 Tesla 博士的对话提供充足话题,同时展现您对他兴趣领域和专业发展的了解。 ``` ```python query = "I need to speak with Dr. Nikola Tesla about recent advancements in wireless energy. Can you help me prepare for this conversation?" response = await alfred.run(query) print("🎩 Alfred's Response:") print(response) ``` 预期输出: ``` 🎩 Alfred's Response: 以下是您与 Nikola Tesla 博士讨论无线能源时可能有用的最新进展: 1. **无线电力传输的进展与挑战**:本文讨论无线电力传输(WPT)从传统有线方式到现代应用(包括太空太阳能电站)的演变,重点介绍微波技术的初期应用及当前电子设备兴起带来的需求。 2. **面向体表电子设备的无线能量传输技术新进展**:探索无线能量传输(WET)作为无电池/导线供电方案的潜力,讨论其优势及潜在应用场景。 3. **无线电力传输与能量收集:现状与未来趋势**:概述无线供能方法的最新进展,包括能量收集和无线输电技术,展示多个前景应用并探讨领域未来趋势。 4. **无线电力传输:应用、挑战与障碍** ``` ```python response = alfred.invoke({"messages":"I need to speak with 'Dr. Nikola Tesla' about recent advancements in wireless energy. Can you help me prepare for this conversation?"}) print("🎩 Alfred's Response:") print(response['messages'][-1].content) ``` 预期输出: ``` 根据提供的信息,以下是准备与 'Dr. Nikola Tesla' 讨论无线能源最新进展的关键要点: 1. **无线电力传输 (WPT)**:探讨如何通过消除线缆需求并利用感应和谐振耦合机制革新能量传输 2. **无线充电进展**:强调效率提升、更快充电速度及 Qi/Qi2 认证解决方案的兴起 3. **5G-Advanced 创新与 NearLink 协议**:作为提升无线网络速度、安全性和效率的技术,可支持先进无线能源应用 4. **边缘 AI/ML**:讨论人工智能如何依赖无线网络实现边缘智能化,提升智能家居自动化水平 5. **Matter 标准与安全增强**:作为推动 IoT 设备连接效率和安全性提升的关键创新 6. **无线充电技术突破**:包括仁川国立大学等机构的最新研究成果 ``` ## 高级功能:对话记忆 为了让 Alfred 在晚会中更智能,我们可以启用对话记忆功能使其记住先前交流: ```python # 创建带记忆的 Alfred alfred_with_memory = CodeAgent( tools=[guest_info_tool, weather_info_tool, hub_stats_tool, search_tool], model=model, add_base_tools=True, planning_interval=3 ) # 首次交互 response1 = alfred_with_memory.run("Tell me about Lady Ada Lovelace.") print("🎩 Alfred's First Response:") print(response1) # 二次交互(引用首次内容) response2 = alfred_with_memory.run("What projects is she currently working on?", reset=False) print("🎩 Alfred's Second Response:") print(response2) ``` ```python from llama_index.core.workflow import Context alfred = AgentWorkflow.from_tools_or_functions( [guest_info_tool, search_tool, weather_info_tool, hub_stats_tool], llm=llm ) # 记忆状态 ctx = Context(alfred) # 首次交互 response1 = await alfred.run("Tell me about Lady Ada Lovelace.", ctx=ctx) print("🎩 Alfred's First Response:") print(response1) # 二次交互(引用首次内容) response2 = await alfred.run("What projects is she currently working on?", ctx=ctx) print("🎩 Alfred's Second Response:") print(response2) ``` ```python # 首次交互 response = alfred.invoke({"messages": [HumanMessage(content="Tell me about 'Lady Ada Lovelace'. What's her background and how is she related to me?")]}) print("🎩 Alfred's Response:") print(response['messages'][-1].content) print() # 二次交互(引用首次内容) response = alfred.invoke({"messages": response["messages"] + [HumanMessage(content="What projects is she currently working on?")]}) print("🎩 Alfred's Response:") print(response['messages'][-1].content) ``` 注意到这三种智能体框架都没有直接集成记忆模块,这种设计有何特殊考量?🧐 * smolagents:记忆在不同执行周期中不保留,需通过 reset=False 显式声明 * LlamaIndex: 需显式添加 context 对象进行运行周期内的记忆管理 * LangGraph: 提供检索历史消息选项或专用 [MemorySaver](https://langchain-ai.github.io/langgraph/tutorials/introduction/#part-3-adding-memory-to-the-chatbot) 组件 ## 结语 恭喜!您已成功构建 Alfred——配备多种工具的智能体助手,可协助举办本世纪最盛大的晚会。Alfred 现在能够: 1. 检索嘉宾详细信息 2. 核查天气条件规划户外活动 3. 提供顶尖 AI 开发者及其模型洞察 4. 网络搜索最新资讯 5. 通过记忆维持对话上下文 凭借这些能力,Alfred 已准备就绪,确保您的晚会取得圆满成功,通过个性化服务和实时信息给宾客留下深刻印象。 ================================================ FILE: units/zh-CN/unit3/agentic-rag/agentic-rag.mdx ================================================ # 智能体增强检索生成(Agentic RAG) 在本单元中,我们将探讨如何利用智能体增强检索生成(Agentic RAG)帮助 Alfred 筹备精彩的晚会。 > [!TIP] > 提示:我们已在先前单元讨论过检索增强生成(RAG)和智能体增强 RAG,如果您已熟悉这些概念可跳过本节。 大语言模型(LLMs)通过海量数据训练获得通用知识。 但其世界知识模型可能包含过时或不相关信息。 **RAG 通过从您的数据中检索相关信息并传递给大语言模型,有效解决了这个问题。** ![RAG 示意图](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/rag.png) 思考 Alfred 的工作流程: 1. 我们要求 Alfred 协助策划晚会 2. Alfred 需要获取最新新闻和天气信息 3. Alfred 需要整理和检索宾客信息 正如 Alfred 需要搜索家庭信息才能提供有效帮助,任何智能体都需要理解和检索相关数据的能力。 **智能体增强 RAG 是帮助智能体解答数据问题的强大工具**,我们可以为 Alfred 提供多种工具来辅助问题解答。 与传统文档自动问答不同,Alfred 可以自主决定使用任何工具或流程来回答问题。 ![智能体增强 RAG 架构](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit2/llama-index/agentic-rag.png) 现在让我们开始**构建智能体增强 RAG 工作流**! 首先创建用于检索最新受邀者详情的 RAG 工具,接着开发网络搜索、天气更新和 Hugging Face Hub 模型下载统计等工具,最终整合所有组件实现我们的智能体增强 RAG 智能体! ================================================ FILE: units/zh-CN/unit3/agentic-rag/conclusion.mdx ================================================ # 总结 在本单元中,我们学习了如何创建智能体增强的检索生成(RAG)系统,帮助我们友好的智能体 Alfred 筹备并管理一场盛大的晚会。 RAG 与智能体能力的结合展示了当 AI 助手具备以下能力时的强大潜力: - 访问结构化知识(宾客信息) - 获取实时信息(网络搜索) - 领域专用工具(天气信息、Hub 统计) - 历史交互记忆 凭借这些能力,Alfred 现已具备完美主持者的素质,能够回答宾客问题、提供最新信息、确保晚会顺利进行——甚至能精准控制烟花表演的时机! > [!TIP] > 完成智能体构建后,您可以进一步探索: > > - 为特定用例创建定制化工具 > - 使用嵌入技术实现更复杂的 RAG 系统 > - 构建可协作的多智能体系统 > - 将智能体部署为可交互的服务 ================================================ FILE: units/zh-CN/unit3/agentic-rag/introduction.mdx ================================================ # 代理增强检索生成(Agentic RAG)用例介绍 ![代理增强 RAG 横幅图](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit3/agentic-rag/thumbnail.jpg) 在本单元中,我们将通过代理增强检索生成(Agentic RAG)技术,帮助负责主持晚会的友好智能体 Alfred 创建用于解答宾客问题的工具。 > [!TIP] > 这是代理增强 RAG 的「真实世界」应用案例,您可直接应用于个人项目或工作场景。若想获得更多实践收获,何不尝试将其应用于您的实际场景并在 Discord 社区分享? 您可以选择课程中讨论的任何框架来实现本用例。我们已在独立标签页中为每个框架提供代码示例。 ## 值得铭记的盛会 现在让我们进入实战环节,为这场盛会搭建舞台! **您决定举办本世纪最奢华、最盛大的派对**——这意味着将包含:豪华宴席、魅惑舞者、知名 DJ、精致饮品、震撼烟花表演等极致元素。 您的好邻居智能体 Alfred 正着手统筹派对的各项需求,**Alfred 将全权管理所有事务**。为此,他需要掌握包括菜单、宾客名单、日程安排、天气预报等在内的完整派对信息! 除此之外,他还需确保派对圆满成功,因此**必须具备在派对期间实时解答各类问题的能力**,同时处理可能出现的突发状况。 Alfred 无法孤军奋战,我们需要确保他能够获取所需的所有信息和工具。 首先,让我们为晚会制定核心需求清单。 ## 晚会核心需求 在**文艺复兴时期**,真正受过良好教育的人需具备三大核心素养: 需精通**体育、文化与科学知识**。因此,我们必须通过知识储备给宾客留下深刻印象,呈现真正难忘的盛会。 但为避免冲突,**政治与宗教等敏感话题应在晚会中回避**,确保派对氛围轻松愉快,不涉及信仰与理念分歧。 根据礼仪规范,**优秀的主办方应充分了解宾客背景**,包括其兴趣爱好与事业成就。同时应善于通过宾客间的故事分享促进交流。 最后,我们还需掌握**基础天气知识**,以便实时获取更新信息,精准把握烟花表演时机,为晚会画上完美句号!🎆 由此可见,Alfred 需要大量信息支持才能办好晚会。 幸运的是,我们可以通过**检索增强生成(RAG)训练**为 Alfred 做好准备! 现在让我们开始创建 Alfred 主持晚会所需的工具集! ================================================ FILE: units/zh-CN/unit3/agentic-rag/invitees.mdx ================================================ # 创建宾客信息检索生成(RAG)工具 您信赖的智能体 Alfred 正在筹备本世纪最盛大的晚会。为确保活动顺利进行,Alfred 需要快速获取最新宾客信息。让我们通过定制化的检索增强生成(RAG)工具(基于专属数据集)为 Alfred 赋能。 ## 为何选择 RAG 技术? 试想 Alfred 在宾客间穿梭时需即时调取详细信息,传统大语言模型(LLM)可能面临以下挑战: 1. 宾客名单属于特定活动数据,不在模型训练范围内 2. 宾客信息可能频繁变更或更新 3. 需精确检索电子邮件地址等细节信息 这正是检索增强生成(RAG)技术的优势所在!通过结合检索系统与 LLM,Alfred 可按需获取准确、实时的宾客信息。 > [!TIP] > 您可以选择课程涵盖的任何框架实现本用例,请通过代码标签页选择偏好方案。 ## 应用搭建 我们将以 Hugging Face Space 为开发环境,采用结构化 Python 项目构建智能体。这种架构通过功能模块化实现代码整洁,更贴近实际部署场景。 ### 项目结构 - **`tools.py`** – 为智能体提供辅助工具 - **`retriever.py`** – 实现支持知识访问的检索功能 - **`app.py`** – 整合所有组件形成完整功能智能体(将在本单元最后完成) 实操参考:[Hugging Face Space 示例](https://huggingface.co/spaces/agents-course/Unit_3_Agentic_RAG),该空间已部署本单元开发的智能体增强 RAG 系统,欢迎克隆体验! 可直接测试下方智能体: ## 数据集概览 数据集 [`agents-course/unit3-invitees`](https://huggingface.co/datasets/agents-course/unit3-invitees/) 包含以下字段: - **Name**: 宾客全名 - **Relation**: 与主办方关系 - **Description**: 简要传记或趣闻 - **Email Address**: 邀请函发送及跟进联系方式 数据集预览: > [!TIP] > 实际场景可扩展数据集字段,包含饮食偏好、礼品兴趣、禁忌话题等对主持人有用的详细信息。 ## 构建宾客信息工具 我们将创建 Alfred 在晚会期间快速检索宾客信息的定制工具,分三步实现: 1. 加载并预处理数据集 2. 创建检索工具 3. 工具与 Alfred 集成 ### 步骤一:加载并预处理数据集 首先将原始宾客数据转换为适合检索的格式: ```python import datasets from langchain_core.documents import Document # 加载数据集 guest_dataset = datasets.load_dataset("agents-course/unit3-invitees", split="train") # 转换为 Document 对象 docs = [ Document( page_content="\n".join([ f"Name: {guest['name']}", f"Relation: {guest['relation']}", f"Description: {guest['description']}", f"Email: {guest['email']}" ]), metadata={"name": guest["name"]} ) for guest in guest_dataset ] ``` 我们将使用 Hugging Face `datasets` 库来加载数据集并将其转换为来自 `llama_index.core.schema` 模块的 `Document` 对象列表。 ```python import datasets from llama_index.core.schema import Document # 加载数据集 guest_dataset = datasets.load_dataset("agents-course/unit3-invitees", split="train") # 转换为 Document 对象 docs = [ Document( text="\n".join([ f"Name: {guest_dataset['name'][i]}", f"Relation: {guest_dataset['relation'][i]}", f"Description: {guest_dataset['description'][i]}", f"Email: {guest_dataset['email'][i]}" ]), metadata={"name": guest_dataset['name'][i]} ) for i in range(len(guest_dataset)) ] ``` 我们将使用 Hugging Face `datasets` 库来加载数据集并将其转换为来自 `langchain.docstore.document` 模块的 `Document` 对象列表。 ```python import datasets from langchain_core.documents import Document # 加载数据集 guest_dataset = datasets.load_dataset("agents-course/unit3-invitees", split="train") # 转换为 Document 对象 docs = [ Document( page_content="\n".join([ f"Name: {guest['name']}", f"Relation: {guest['relation']}", f"Description: {guest['description']}", f"Email: {guest['email']}" ]), metadata={"name": guest["name"]} ) for guest in guest_dataset ] ``` 在上面的代码中,我们: - 加载数据集 - 将每条房客记录转换为包含格式化内容的 “Document” 对象 - 将 “Document” 对象存储在列表中 这意味着我们已经准备好所有数据,可以开始配置检索功能了。 ### 步骤 2:创建检索工具 现在,让我们创建一个自定义工具,Alfred 可以使用它来搜索房客信息。 我们将使用“langchain_community.retrievers”模块中的“BM25Retriever”来创建一个检索工具。 > [!TIP] > BM25Retriever 是检索的一个很好的起点,但对于更高级的语义搜索,您可以考虑使用基于嵌入的检索器,例如来自 sentence-transformers 的检索器。 ```python from smolagents import Tool from langchain_community.retrievers import BM25Retriever class GuestInfoRetrieverTool(Tool): name = "guest_info_retriever" description = "Retrieves detailed information about gala guests based on their name or relation." inputs = { "query": { "type": "string", "description": "The name or relation of the guest you want information about." } } output_type = "string" def __init__(self, docs): self.is_initialized = False self.retriever = BM25Retriever.from_documents(docs) def forward(self, query: str): results = self.retriever.get_relevant_documents(query) if results: return "\n\n".join([doc.page_content for doc in results[:3]]) else: return "No matching guest information found." # 初始化工具 guest_info_tool = GuestInfoRetrieverTool(docs) ``` 让我们逐步了解这个工具: - `name` 和 `description` 帮助智能体了解何时以及如何使用此工具 - `inputs` 定义工具所需的参数(在本例中为搜索查询) - 我们使用 `BM25Retriever`,这是一种强大的文本检索算法,不需要嵌入 - `forward` 方法处理查询并返回最相关的客人信息 我们将使用 `llama_index.retrievers.bm25` 模块中的 `BM25Retriever` 来创建一个检索工具。 > [!TIP] > BM25Retriever 是一个很好的检索起点,但对于更高级的语义搜索,您可以考虑使用基于嵌入的检索器,例如 sentence-transformers 中的检索器。 ```python from llama_index.core.tools import FunctionTool from llama_index.retrievers.bm25 import BM25Retriever bm25_retriever = BM25Retriever.from_defaults(nodes=docs) def get_guest_info_retriever(query: str) -> str: """Retrieves detailed information about gala guests based on their name or relation.""" results = bm25_retriever.retrieve(query) if results: return "\n\n".join([doc.text for doc in results[:3]]) else: return "No matching guest information found." # 初始化工具 guest_info_tool = FunctionTool.from_defaults(get_guest_info_retriever) ``` 让我们逐步了解这个工具。 - 文档字符串帮助智能体了解何时以及如何使用此工具 - 类型装饰器定义了工具所需的参数(在本例中为搜索查询) - 我们使用 `BM25Retriever`,这是一种强大的文本检索算法,不需要嵌入 - 该方法处理查询并返回最相关的客人信息 我们将使用 `langchain_community.retrievers` 模块中的 `BM25Retriever` 来创建一个检索工具。 > [!TIP] > BM25Retriever 是一个很好的检索起点,但对于更高级的语义搜索,您可以考虑使用基于嵌入的检索器,例如 sentence-transformers 中的检索器。 ```python from langchain_community.retrievers import BM25Retriever from langchain_core.tools import Tool bm25_retriever = BM25Retriever.from_documents(docs) def extract_text(query: str) -> str: """Retrieves detailed information about gala guests based on their name or relation.""" results = bm25_retriever.invoke(query) if results: return "\n\n".join([doc.page_content for doc in results[:3]]) else: return "No matching guest information found." guest_info_tool = Tool( name="guest_info_retriever", func=extract_text, description="Retrieves detailed information about gala guests based on their name or relation." ) ``` 让我们逐步了解这个工具。 - `name` 和 `description` 帮助智能体了解何时以及如何使用此工具。 - 类型装饰器定义了工具所需的参数(在本例中为搜索查询)。 - 我们使用 `BM25Retriever`,这是一种强大的文本检索算法,无需嵌入。 - 该方法处理查询并返回最相关的客人信息。 ### 步骤 3:将工具与 Alfred 集成 最后,让我们创建智能体并为其配备自定义工具,将所有内容整合在一起: ```python from smolagents import CodeAgent, InferenceClientModel # 初始化 Hugging Face 模型 model = InferenceClientModel() # 使用宾客信息工具创建我们的晚会智能体 Alfred alfred = CodeAgent(tools=[guest_info_tool], model=model) # Example query Alfred might receive during the gala response = alfred.run("Tell me about our guest named 'Lady Ada Lovelace'.") print("🎩 Alfred's Response:") print(response) ``` 预期输出: ``` 🎩 Alfred's Response: 根据我检索到的信息,艾达·洛夫莱斯夫人是一位受人尊敬的数学家和朋友。她因其在数学和计算机领域的开创性工作而闻名,并因其在查尔斯·巴贝奇的分析机方面的贡献而被誉为第一位计算机程序员。她的电子邮件地址是 ada.lovelace@example.com。 ``` 这最后一步具体做了什么: - 我们使用 `InferenceClientModel` 类初始化 Hugging Face 模型 - 我们将智能体 (Alfred) 创建为 `CodeAgent`,它可以执行 Python 代码来解决问题 - 我们让 Alfred 检索一位名叫“Lady Ada Lovelace”的客人的信息 ```python from llama_index.core.agent.workflow import AgentWorkflow from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI # 初始化 Hugging Face 模型 llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") # 使用宾客信息工具创建我们的晚会智能体 Alfred alfred = AgentWorkflow.from_tools_or_functions( [guest_info_tool], llm=llm, ) # Example query Alfred might receive during the gala response = await alfred.run("Tell me about our guest named 'Lady Ada Lovelace'.") print("🎩 Alfred's Response:") print(response) ``` 预期输出: ``` 🎩 Alfred's Response: Lady Ada Lovelace 是一位受人尊敬的数学家和朋友,因其在数学和计算领域的开创性工作而闻名。她因参与查尔斯·巴贝奇的分析机研究而被誉为第一位计算机程序员。她的邮箱是 ada.lovelace@example.com。 ``` 这最后一步具体做了什么: - 我们使用 `HuggingFaceInferenceAPI` 类初始化 Hugging Face 模型 - 我们将智能体 (Alfred) 创建为 `AgentWorkflow`,其中包含我们刚刚创建的工具 - 我们请求 Alfred 检索名为“Lady Ada Lovelace”的客人的信息 ```python from typing import TypedDict, Annotated from langgraph.graph.message import add_messages from langchain_core.messages import AnyMessage, HumanMessage, AIMessage from langgraph.prebuilt import ToolNode from langgraph.graph import START, StateGraph from langgraph.prebuilt import tools_condition from langchain_huggingface import HuggingFaceEndpoint, ChatHuggingFace # 生成聊天界面,包括工具 llm = HuggingFaceEndpoint( repo_id="Qwen/Qwen2.5-Coder-32B-Instruct", huggingfacehub_api_token=HUGGINGFACEHUB_API_TOKEN, ) chat = ChatHuggingFace(llm=llm, verbose=True) tools = [guest_info_tool] chat_with_tools = chat.bind_tools(tools) # 生成 AgentState 和 Agent 图 class AgentState(TypedDict): messages: Annotated[list[AnyMessage], add_messages] def assistant(state: AgentState): return { "messages": [chat_with_tools.invoke(state["messages"])], } ## 构建流程图 builder = StateGraph(AgentState) # 定义节点:这些节点完成工作 builder.add_node("assistant", assistant) builder.add_node("tools", ToolNode(tools)) # 定义边:这些决定了控制流如何移动 builder.add_edge(START, "assistant") builder.add_conditional_edges( "assistant", # If the latest message requires a tool, route to tools # Otherwise, provide a direct response tools_condition, ) builder.add_edge("tools", "assistant") alfred = builder.compile() messages = [HumanMessage(content="Tell me about our guest named 'Lady Ada Lovelace'.")] response = alfred.invoke({"messages": messages}) print("🎩 Alfred's Response:") print(response['messages'][-1].content) ``` 预期输出: ``` 🎩 Alfred's Response: Lady Ada Lovelace 是一位受人尊敬的数学家和计算机领域的先驱,由于她在查尔斯·巴贝奇的分析机上所做的工作,她经常被誉为第一位计算机程序员。 ``` 这最后一步具体做了什么: - 我们使用 `HuggingFaceEndpoint` 类初始化 Hugging Face 模型。我们还生成了一个聊天界面并附加了工具。 - 我们将智能体 (Alfred) 创建为一个 `StateGraph`,它使用一条边连接两个节点(`Assistant` 和 `tools`)。 - 我们让 Alfred 检索一位名叫“Lady Ada Lovelace”的客人的信息。 ## 互动示例 在晚会上,对话可能像这样进行: **你**:“Alfred,那位正在和大使说话的先生是谁?” **Alfred** *快速搜索嘉宾数据库* “先生,那是尼古拉·特斯拉博士。他是你大学时代的老朋友。他最近申请了一种新的无线能量传输系统的专利,很乐意和你讨论一下。不过别忘了,他对鸽子很感兴趣,所以这或许会成为一次很好的闲聊。” ```json { "name": "Dr. Nikola Tesla", "relation": "old friend from university days", "description": "Dr. Nikola Tesla is an old friend from your university days. He's recently patented a new wireless energy transmission system and would be delighted to discuss it with you. Just remember he's passionate about pigeons, so that might make for good small talk.", "email": "nikola.tesla@gmail.com" } ``` ## 更进一步 既然 Alfred 可以检索宾客信息,不妨考虑如何增强这个系统: 1. **改进检索器**,使用更复杂的算法,例如 [sentence-transformers](https://www.sbert.net/) 2. **实现对话记忆**,让 Alfred 记住之前的互动 3. **结合网页搜索**,获取陌生宾客的最新信息 4. **整合多个索引**,从经过验证的来源获取更完整的信息 现在,Alfred 已经完全有能力轻松处理宾客的咨询,确保您的晚会成为本世纪最精致、最令人愉悦的盛事! <提示> 尝试扩展检索工具,使其能够根据每位宾客的兴趣或背景返回对话开场白。您将如何修改该工具来实现这一点? 完成后,在 retriever.py 文件中实现您的宾客检索工具。 ================================================ FILE: units/zh-CN/unit3/agentic-rag/tools.mdx ================================================ # 构建并集成智能体工具 节将为 Alfred 赋予网络访问能力,使其能够获取实时新闻与全球资讯。 同时还将集成天气数据和 Hugging Face Hub 模型下载统计功能,帮助其进行时效性话题交流。 ## 赋予智能体网络访问能力 请记住,我们希望 Alfred 能够展现出一位真正的文艺复兴主持人的风采,并对世界有着深刻的了解。 为此,我们需要确保 Alfred 能够获取有关世界的最新新闻和信息。 让我们从为 Alfred 创建一个网络搜索工具开始吧! ```python from smolagents import DuckDuckGoSearchTool # 初始化 DuckDuckGo 搜索工具 search_tool = DuckDuckGoSearchTool() # 示例用法 results = search_tool("Who's the current President of France?") print(results) ``` 预期输出: ``` 法国现任总统为 Emmanuel Macron。 ``` ```python from llama_index.tools.duckduckgo import DuckDuckGoSearchToolSpec from llama_index.core.tools import FunctionTool # 初始化 DuckDuckGo 搜索工具 tool_spec = DuckDuckGoSearchToolSpec() search_tool = FunctionTool.from_defaults(tool_spec.duckduckgo_full_search) # 示例用法 response = search_tool("Who's the current President of France?") print(response.raw_output[-1]['body']) ``` 预期输出: ``` 法兰西共和国总统是法国的国家元首。现任总统是 Emmanuel Macron,于2017年5月14日就任,并在2017年5月7日举行的总统选举第二轮中击败 Marine Le Pen。法国第五共和国总统名单 编号 肖像 姓名 ... ``` ```python from langchain_community.tools import DuckDuckGoSearchRun search_tool = DuckDuckGoSearchRun() results = search_tool.invoke("Who's the current President of France?") print(results) ``` 预期输出: ``` Emmanuel Macron (1977年12月21日生于亚眠)法国政治家,2017年当选总统... ``` ## 创建天气信息工具(烟花调度) 完美的庆典应该在晴朗的天空下燃放烟花,我们需要确保烟花不会因为恶劣天气而取消。 让我们创建一个自定义工具,用于调用外部天气 API 并获取指定位置的天气信息。 > [!TIP] > 为了简单起见,我们在本例中使用了一个虚拟的天气 API。如果您想使用真实的天气 API,您可以实现一个使用 OpenWeatherMap API 的天气工具,就像Unit 1中提到的那样。 ```python from smolagents import Tool import random class WeatherInfoTool(Tool): name = "weather_info" description = "Fetches dummy weather information for a given location." inputs = { "location": { "type": "string", "description": "The location to get weather information for." } } output_type = "string" def forward(self, location: str): # 虚拟天气数据 weather_conditions = [ {"condition": "Rainy", "temp_c": 15}, {"condition": "Clear", "temp_c": 25}, {"condition": "Windy", "temp_c": 20} ] # 随机选择一种天气状况 data = random.choice(weather_conditions) return f"Weather in {location}: {data['condition']}, {data['temp_c']}°C" # 初始化工具 weather_info_tool = WeatherInfoTool() ``` ```python import random from llama_index.core.tools import FunctionTool def get_weather_info(location: str) -> str: """Fetches dummy weather information for a given location.""" # 虚拟天气数据 weather_conditions = [ {"condition": "Rainy", "temp_c": 15}, {"condition": "Clear", "temp_c": 25}, {"condition": "Windy", "temp_c": 20} ] # 随机选择一种天气状况 data = random.choice(weather_conditions) return f"Weather in {location}: {data['condition']}, {data['temp_c']}°C" # 初始化工具 weather_info_tool = FunctionTool.from_defaults(get_weather_info) ``` ```python from langchain_core.tools import Tool import random def get_weather_info(location: str) -> str: """Fetches dummy weather information for a given location.""" # 虚拟天气数据 weather_conditions = [ {"condition": "Rainy", "temp_c": 15}, {"condition": "Clear", "temp_c": 25}, {"condition": "Windy", "temp_c": 20} ] # 随机选择一种天气状况 data = random.choice(weather_conditions) return f"Weather in {location}: {data['condition']}, {data['temp_c']}°C" # 初始化工具 weather_info_tool = Tool( name="get_weather_info", func=get_weather_info, description="Fetches dummy weather information for a given location." ) ``` ## 为有影响力的 AI 开发者创建 Hub 统计工具 出席此次盛会的都是 AI 开发者的精英。Alfred 希望通过讨论他们最受欢迎的模型、数据集和空间来给他们留下深刻印象。我们将创建一个工具,根据用户名从 Hugging Face Hub 获取模型统计数据。 ```python from smolagents import Tool from huggingface_hub import list_models class HubStatsTool(Tool): name = "hub_stats" description = "Fetches the most downloaded model from a specific author on the Hugging Face Hub." inputs = { "author": { "type": "string", "description": "The username of the model author/organization to find models from." } } output_type = "string" def forward(self, author: str): try: # 列出指定作者的模型,按下载次数排序 models = list(list_models(author=author, sort="downloads", direction=-1, limit=1)) if models: model = models[0] return f"The most downloaded model by {author} is {model.id} with {model.downloads:,} downloads." else: return f"No models found for author {author}." except Exception as e: return f"Error fetching models for {author}: {str(e)}" # 初始化工具 hub_stats_tool = HubStatsTool() # 示例用法 print(hub_stats_tool("facebook")) # Example: Get the most downloaded model by Facebook ``` 预期输出: ``` Facebook 下载次数最多的模型是 facebook/esmfold_v1,下载次数为 12,544,550 次。 ``` ```python import random from llama_index.core.tools import FunctionTool from huggingface_hub import list_models def get_hub_stats(author: str) -> str: """Fetches the most downloaded model from a specific author on the Hugging Face Hub.""" try: # 列出指定作者的模型,按下载次数排序 models = list(list_models(author=author, sort="downloads", direction=-1, limit=1)) if models: model = models[0] return f"The most downloaded model by {author} is {model.id} with {model.downloads:,} downloads." else: return f"No models found for author {author}." except Exception as e: return f"Error fetching models for {author}: {str(e)}" # 初始化工具 hub_stats_tool = FunctionTool.from_defaults(get_hub_stats) # 示例用法 print(hub_stats_tool("facebook")) # Example: Get the most downloaded model by Facebook ``` 预期输出: ``` Facebook 下载次数最多的模型是 facebook/esmfold_v1,下载次数为 12,544,550 次。 ``` ```python from langchain_core.tools import Tool from huggingface_hub import list_models def get_hub_stats(author: str) -> str: """Fetches the most downloaded model from a specific author on the Hugging Face Hub.""" try: # 列出指定作者的模型,按下载次数排序 models = list(list_models(author=author, sort="downloads", direction=-1, limit=1)) if models: model = models[0] return f"The most downloaded model by {author} is {model.id} with {model.downloads:,} downloads." else: return f"No models found for author {author}." except Exception as e: return f"Error fetching models for {author}: {str(e)}" # 初始化工具 hub_stats_tool = Tool( name="get_hub_stats", func=get_hub_stats, description="Fetches the most downloaded model from a specific author on the Hugging Face Hub." ) # 示例用法 print(hub_stats_tool.invoke("facebook")) # Example: Get the most downloaded model by Facebook ``` 预期输出: ``` Facebook 下载次数最多的模型是 facebook/esmfold_v1,下载次数为 13,109,861 次。 ``` 借助 Hub Stats 工具,Alfred 现在可以通过讨论他们最受欢迎的模型来打动有影响力的 AI 开发者。 ## 将工具与 Alfred 集成 现在我们已经拥有了所有工具,让我们将它们集成到 Alfred 的智能体中: ```python from smolagents import CodeAgent, InferenceClientModel # 初始化 Hugging Face 模型 model = InferenceClientModel() # 使用所有工具创建 Alfred alfred = CodeAgent( tools=[search_tool, weather_info_tool, hub_stats_tool], model=model ) # Alfred 在庆典期间可能会收到的示例查询 response = alfred.run("What is Facebook and what's their most popular model?") print("🎩 Alfred's Response:") print(response) ``` 预期输出: ``` 🎩 Alfred's Response: Facebook 是一个社交网站,用户可以在这里互相联系、分享信息并互动。Facebook 在 Hugging Face Hub 上下载次数最多的模型是 ESMFold_v1。 ``` ```python from llama_index.core.agent.workflow import AgentWorkflow from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI # 初始化 Hugging Face 模型 llm = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct") # 使用所有工具创建 Alfred alfred = AgentWorkflow.from_tools_or_functions( [search_tool, weather_info_tool, hub_stats_tool], llm=llm ) # Alfred 在庆典期间可能会收到的示例查询 response = await alfred.run("What is Facebook and what's their most popular model?") print("🎩 Alfred's Response:") print(response) ``` 预期输出: ``` 🎩 Alfred's Response: Facebook 是一家总部位于加利福尼亚州门洛帕克的社交网络服务和科技公司。它由马克·扎克伯格创立,允许用户创建个人资料、与亲朋好友联系、分享照片和视频,以及加入基于共同兴趣的群组。Facebook 在 Hugging Face Hub 上最受欢迎的模型是“facebook/esmfold_v1”,下载量达 13,109,861 次。 ``` ```python from typing import TypedDict, Annotated from langgraph.graph.message import add_messages from langchain_core.messages import AnyMessage, HumanMessage, AIMessage from langgraph.prebuilt import ToolNode from langgraph.graph import START, StateGraph from langgraph.prebuilt import tools_condition from langchain_huggingface import HuggingFaceEndpoint, ChatHuggingFace # 生成聊天界面,包括工具 llm = HuggingFaceEndpoint( repo_id="Qwen/Qwen2.5-Coder-32B-Instruct", huggingfacehub_api_token=HUGGINGFACEHUB_API_TOKEN, ) chat = ChatHuggingFace(llm=llm, verbose=True) tools = [search_tool, weather_info_tool, hub_stats_tool] chat_with_tools = chat.bind_tools(tools) # 生成 AgentState 和 Agent 图 class AgentState(TypedDict): messages: Annotated[list[AnyMessage], add_messages] def assistant(state: AgentState): return { "messages": [chat_with_tools.invoke(state["messages"])], } ## 构建流程图 builder = StateGraph(AgentState) # 定义节点:这些节点完成工作 builder.add_node("assistant", assistant) builder.add_node("tools", ToolNode(tools)) # 定义边:这些决定了控制流如何移动 builder.add_edge(START, "assistant") builder.add_conditional_edges( "assistant", # If the latest message requires a tool, route to tools # Otherwise, provide a direct response tools_condition, ) builder.add_edge("tools", "assistant") alfred = builder.compile() messages = [HumanMessage(content="Who is Facebook and what's their most popular model?")] response = alfred.invoke({"messages": messages}) print("🎩 Alfred's Response:") print(response['messages'][-1].content) ``` 预期输出: ``` 🎩 Alfred's Response: Facebook 是一家社交媒体公司,以其社交网站 Facebook 以及 Instagram 和 WhatsApp 等其他服务而闻名。Facebook 在 Hugging Face Hub 上下载次数最多的模型是 facebook/esmfold_v1,下载量达 13,202,321 次。 ``` ## 结论 通过集成这些工具,Alfred 现在可以处理各种任务,从网页搜索到天气更新和模型统计。这确保他始终是晚会上最了解情况、最有魅力的主持人。 > [!TIP] > 尝试实现一个可用于获取特定主题最新消息的工具。 > > 完成后,在 tools.py 文件中实现您的自定义工具。 ================================================ FILE: units/zh-CN/unit4/additional-readings.mdx ================================================ # 那现在呢?我应该学习哪些主题? Agentic AI 是一个快速发展的领域,了解基础协议对于构建智能自主系统至关重要。 你应该熟悉的两个重要标准是: - **模型上下文协议 (MCP)** - **代理对代理协议 (A2A)** ## 🔌 模型上下文协议 (MCP) Anthropic 的 **模型上下文协议 (MCP)** 是一个开放标准,使 AI 模型能够安全无缝地**连接外部工具、数据源和应用程序**,从而使代理更加智能和自主。 可以将 MCP 想象为一个**通用适配器**,就像 USB-C 接口一样,使 AI 模型能够插入各种数字环境**而无需为每一个进行定制集成**。 MCP 正在迅速获得行业关注,开始被OpenAI 和谷歌等大公司所采用它。 📚 了解更多: - [Anthropic 的官方公告和文档](https://www.anthropic.com/news/model-context-protocol) - [MCP - 维基百科](https://en.wikipedia.org/wiki/Model_Context_Protocol) - [MCP - 博客](https://huggingface.co/blog/Kseniase/mcp) ## 🤝 代理对代理 (A2A) 协议 谷歌开发了 **代理对代理 (A2A) 协议**,作为 Anthropic 的模型上下文协议 (MCP) 的补充。 虽然 MCP 连接代理与外部工具,**A2A 则连接代理之间**,为多智能体系统之间的协作铺平道路,使其能够协同工作以解决复杂问题。 📚 深入了解 A2A: - [谷歌的 A2A 公告](https://developers.googleblog.com/en/a2a-a-new-era-of-agent-interoperability/) ================================================ FILE: units/zh-CN/unit4/conclusion.mdx ================================================ # 结论 **恭喜你完成Agent课程!** 经过不懈坚持和投入,你已经在AI智能体方面打下了坚实的基础。 但完成这个课程**并不是你旅程的终点**。这只是一个开始:不要在探索下一个章节方面犹豫,我们在那里分享了更多我们精选的资源,以帮助你继续学习,包括像**MCPs**等进阶资源。 **谢谢你**参与这个课程。**我们希望您喜欢这门课程,就像我们享受这个课程的编写那样**。 別忘了:**持续学习,保持卓越🤗** ================================================ FILE: units/zh-CN/unit4/get-your-certificate.mdx ================================================ # 领取你的证书 🎓 如果你得分**高于30%,恭喜你!👏 你现在有资格领取你的官方证书**。 你可以按照以下步骤领取: 1. 访问[证书页面](https://huggingface.co/spaces/agents-course/Unit4-Final-Certificate)。 2. 使用提供的按钮**登录**你的 Hugging Face 账户。 3. **输入你的全名**,这将是显示在你证书上的名字。 4. 点击“**获取我的证书**”来验证你的分数并下载你的证书。 Congrats! 拿到证书后,你可以随意: - 将其添加到你的 **LinkedIn个人资料** 🧑‍💼 - 在**X**、**Bluesky**等平台分享 🎉 **别忘了[@huggingface](https://huggingface.co/huggingface)。我们会为你感到无比自豪,并且很高兴和你庆祝!🤗** ================================================ FILE: units/zh-CN/unit4/hands-on.mdx ================================================ # 动手实践 现在你已经准备好更深入地创建你的最终智能体了,让我们看看如何提交它以供评审。 ## 数据集 此排行榜使用的数据集包含从 GAIA **验证**集的一级问题中所提取的 20 个问题。 这些问题是根据回答问题所需的工具和步骤数量进行筛选的。 根据 GAIA 基准目前的状况,我们认为让你尝试在一级问题中达到 30% 的准确率是一个相对好的测试。 GAIA current status! ## 流程 现在你脑海中最大的问题可能是:“我如何开始提交?” 对于本单元,我们创建了一个 API,你可以通过它获取问题并发送答案进行评分。 以下是路由摘要(请参阅[实时文档](https://agents-course-unit4-scoring.hf.space/docs)以获取交互式详细信息): * **`GET /questions`**:检索过滤后的评估问题完整列表。 * **`GET /random-question`**:从列表中获取一个随机问题。 * **`GET /files/{task_id}`**:下载与给定任务 ID 关联的特定文件。 * **`POST /submit`**:提交智能体的答案,计算分数,并更新排行榜。 提交函数将以**完全匹配**的方式将答案与真实答案进行比较,因此请好好作出提示!GAIA 团队在此处分享了一个代理提示示例(为了本课程的目的,请确保你的提交中不包含文本“FINAL ANSWER”,只需让你的代理回复答案而无需其他内容)。 🎨 **打造你自己的模板!** 为了演示与 API 交互的过程,我们提供了一个[基本模板](https://huggingface.co/spaces/agents-course/Final_Assignment_Template)作为开始的部分。 我们请您随意的去更改、添加或完全重构它!以最适合你的方法和具有创造力的方式修改它。这也是我们所**积极鼓励**的方式。 为了提交此模板,请需要计算 API 所需的 3 个内容: * **用户名:** 你的 Hugging Face 用户名(此处通过 Gradio 登录获取),用于识别你的提交。 * **代码链接 (`agent_code`):** 指向你的 Hugging Face Space 代码(`.../tree/main`)的 URL,用于验证目的,因此请保持你的 Space 为公开。 * **答案 (`answers`):** 你的代理生成的响应列表(`{"task_id": ..., "submitted_answer": ...}`),用于评分。 因此,我们鼓励你从复制此[模板](https://huggingface.co/spaces/agents-course/Final_Assignment_Template)到你自己的 huggingface 个人资料开始。 🏆 在[此处](https://huggingface.co/spaces/agents-course/Students_leaderboard)查看排行榜 *温馨提示:此排行榜仅供娱乐!我们知道可以在没有完全验证的情况下提交分数。如果我们看到太多没有公开链接支持的高分,我们可能需要审查、调整或删除一些条目,以保持排行榜的有用性。* 排行榜将显示你的 Space 代码库链接,由于此排行榜仅供学生使用,如果你获得了一个令你骄傲的分数,请保持你的 Space 公开。 ================================================ FILE: units/zh-CN/unit4/introduction.mdx ================================================ # 欢迎来到最后一个单元 [[介绍]] AI Agents Course thumbnail 欢迎来到课程的最后一个单元!🎉 到目前为止,您已经**在AI智能体方面建立了坚实的基础**,从理解其组件到创建自己的智能体。有了这些知识,您现在可以**构建强大的智能体**并在这个快速发展的领域中赶上潮流。 这个单元和应用您所学的知识有关。这是您的**最终动手项目**,完成它是您获得**课程证书**的入场券。 ## 挑战是什么? 您将创建自己的智能体并**使用[GAIA基准](https://huggingface.co/spaces/gaia-benchmark/leaderboard)的一个子集评估其性能**。 为了成功完成课程,您的智能体需要在基准测试中得到**30%或更高**的分数。实现这一目标,您将获得**完成证书**,正式认证您的专业知识。🏅 此外,您还可以查看自己在所有课程参与者中的表现!我们提供了一个专门的[**学生排行榜**](https://huggingface.co/spaces/agents-course/Students_leaderboard),您可以提交自己的成绩,并查看整个社区的进展情况。 > 🚨 **提示:更高级的实践单元** > > 请注意,这个单元转向更实用的动手方法。在这一部分取得成功需要**更高级的编码知识**,并且与课程的前期部分相比,需要您在**较少明确指导**的情况下完成任务。 这听起来很棒,对吧?让我们开始吧!🚀 ================================================ FILE: units/zh-CN/unit4/what-is-gaia.mdx ================================================ # 什么是GAIA? [GAIA](https://huggingface.co/papers/2311.12983) 是一个**用于评估AI助手在需要核心能力组合的真实世界任务上的表现的基准**,这些核心能力包括推理、多模态理解、网页浏览和熟练的工具使用。 此论文介绍了GAIA _"[GAIA: A Benchmark for General AI Assistants](https://huggingface.co/papers/2311.12983)"_。 该基准包含**466个精心策划的问题**,这些问题对人类来说**在概念上简单**,但对当前的AI系统来说却**极具挑战性**。 为了说明差距: - **人类**:约92%的成功率 - **带有插件的GPT-4**:约15% - **深度研究(OpenAI)**:在验证集上的得分为67.36% GAIA突出了AI模型的当前局限性,并提供了一个严格的基准来评估向真正通用AI助手发展的进展。 ## 🌱 GAIA的核心原则 GAIA围绕以下支柱精心设计: - 🔍 **现实世界的难度**:任务需要多步骤推理、多模态理解和工具交互。 - 🧾 **人类可解释性**:尽管对AI来说很难,但每个任务在概念上对人类来说仍然简单易懂。 - 🛡️ **不可游戏化**:正确答案需要完整的任务执行,使得蛮力破解无效。 - 🧰 **评估的简单性**:答案简洁、事实性强且明确———作为一个理想的基准测试。 ## 难度等级 GAIA任务被组织为**三个递增复杂度的等级**,每个等级测试特定技能: - **一级**:需要少于5个步骤和最少的工具使用。 - **二级**:涉及更复杂的推理和多个工具之间的协调以及5-10个步骤。 - **三级**:需要长期规划和各种工具的高级集成。 ![GAIA等级](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit4/gaia_levels.png) ## 困难GAIA等级(Hard GAIA)的问题示例 > 在2008年画作“乌兹别克斯坦的刺绣”中展示的水果中,哪些曾在1949年10月的早餐菜单中被提供,作为后来用于电影《最后航程》的远洋班轮的一部分?请将这些水果以逗号分隔的列表形式给出,按照它们在画作中从12点位置开始的顺时针排列顺序,并使用每种水果的复数形式。 正如您所见,这个问题在几个方面对AI系统提出了挑战: - 需要一个**结构化的响应格式** - 涉及**多模态推理**(例如,分析图像) - 需要**多跳检索**相互依赖的事实: - 识别画作中的水果 - 发现哪个远洋班轮用于*最后航程* - 查找该船1949年10月的早餐菜单 - 需要**正确的排序**和高级规划以按正确顺序解决 这种任务突出了单独的LLM往往不足的地方,使GAIA成为**基于智能体的系统**的理想基准,这些系统可以在多个步骤和模态上进行推理、检索和执行。 ![GAIA capabilities plot](https://huggingface.co/datasets/agents-course/course-images/resolve/main/en/unit4/gaia_capabilities.png) ## 实时评估 为了鼓励持续的基准测试,**GAIA在Hugging Face上提供了一个公共排行榜**,您可以在其中测试您的模型对**300个测试问题**的表现。 👉 在[这里](https://huggingface.co/spaces/gaia-benchmark/leaderboard)查看排行榜 想深入了解GAIA? - 📄 [阅读完整论文](https://huggingface.co/papers/2311.12983) - 📄 [OpenAI的深度研究发布文章](https://openai.com/index/introducing-deep-research/) - 📄 [开源DeepResearch – 释放我们的搜索智能体](https://huggingface.co/blog/open-deep-research)