Главная/Блог/Аналитика/Создание финансовых AI-агентов на базе…
Аналитика12 мин чтения · 27 июля 2026 г.

Создание финансовых AI-агентов на базе Claude: Полный гайд

Разбираем архитектуру Skill-driven AI-агентов для финансового анализа. Учимся использовать репозиторий Anthropic, Python-инструменты и MCP-коннекторы для DCF, сравнительного анализа и создания инвестиционных меморандумов.

Создание финансовых AI-агентов на базе Claude: Полный гайд

В эпоху, когда искусственный интеллект перестает быть просто генератором текста и становится полноценным аналитиком, перед финансовыми специалистами открывается новая парадигма работы. Представьте себе систему, которая не просто отвечает на вопросы, но и самостоятельно проводит сложные расчеты, строит графики, формирует Excel-отчеты и пишет инвестиционные меморандумы, строго следуя заданным методологиям. Именно такой подход демонстрирует репозиторий Anthropic’s financial-services, который служит основой для создания «агентов, управляемых навыками» (skill-driven agents).

В этой статье мы подробно разберем, как воспроизвести эту архитектуру на чистом Python. Мы не просто скопируем код — мы поймем, как устроена система «под капотом»: от парсинга файлов навыков (SKILL.md) до организации цикла взаимодействия с API Anthropic (Claude) через инструменты (tools). Это руководство для тех, кто хочет перейти от простых чат-ботов к профессиональным финансовым ассистентам, способным выполнять работу аналитика уровня Middle+.

01Архитектура: От репозитория к работающему агенту

Фундамент всей системы — это структурированный репозиторий, содержащий не просто код, а методологии. В нем есть агенты, вертикальные плагины, интеграции партнеров и, что самое важное, cookbooks (кулинарные книги) для управляемых агентов. Каждая «навык» (skill) описывается в файле SKILL.md, который содержит YAML-метаданные и тело инструкции. Это позволяет системе динамически подгружать только те инструкции, которые нужны для конкретной задачи.

Наша задача — создать обертку, которая:

  1. Сканирует репозиторий и создает реестр всех доступных навыков.
  2. Позволяет пользователю выбрать нужный навык (например, «DCF» или «Comps»).
  3. Встраивает выбранные инструкции в системный промпт модели Claude.
  4. Предоставляет модели инструменты для выполнения расчетов на Python и сохранения файлов.
  5. Управляет циклом «вопрос-ответ-инструмент» до получения финального результата.

Такой подход обеспечивает воспроизводимость и контроль. Модель не «фантазирует» о формулах, а строго следует алгоритму, заложенному в файл навыка.

Создание финансовых AI-агентов на базе Claude: Полный гайд

02Шаг 1: Подготовка окружения и репозитория

Первым делом необходимо подготовить среду. Мы будем использовать Google Colab или локальный Python-окружение. Ключевые библиотеки: anthropic для работы с API, pandas для данных, openpyxl для Excel, matplotlib для графиков и pyyaml для парсинга инструкций.

Важный момент: мы клонируем репозиторий anthropics/financial-services с параметром --depth 1, чтобы не скачивать всю историю коммитов, а получить только актуальную версию. Это экономит время и место.

terminalpython
import subprocess
import sys
import os
import io
import re
import json
import glob
import textwrap
import contextlib
from pathlib import Path

def sh(cmd):
    print(f"$ {cmd}")
    result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
    if result.returncode != 0:
        print(result.stderr[:1500])
    return result

sh(f"{sys.executable} -m pip install -q anthropic pandas openpyxl pyyaml matplotlib")

import pandas as pd
import yaml
import matplotlib.pyplot as plt

REPO_URL = "https://github.com/anthropics/financial-services.git"
REPO_DIR = "financial-services"

if not os.path.isdir(REPO_DIR):
    sh(f"git clone --depth 1 {REPO_URL} {REPO_DIR}")
else:
    print("Repo already cloned — skipping.")

Для работы с API ключом мы используем гибкий подход: сначала проверяем переменные окружения, затем секреты Google Colab, и только в крайнем случае запрашиваем ввод вручную. Это обеспечивает безопасность и удобство при автоматизации.

03Шаг 2: Сканирование репозитория и создание реестра навыков

Чтобы агент знал, что он умеет, мы должны «показать» ему все доступные инструменты. Функция repo_map проходит по структуре папок, находит файлы SKILL.md и конфигурации MCP (Model Context Protocol), и формирует DataFrame с информацией о каждом плагине.

Особое внимание уделяем классу SkillRegistry. Он парсит каждый файл SKILL.md, извлекает заголовок, описание и тело инструкции. Затем он создает словарь, где ключом является название навыка, а значением — объект Skill. Это позволяет быстро искать нужные инструкции по ключевым словам.

Создание финансовых AI-агентов на базе Claude: Полный гайд
terminalpython
class Skill:
    def __init__(self, path):
        self.path = path
        raw = open(path, encoding="utf-8", errors="replace").read()
        FRONTMATTER = re.compile(r"^---\s*\n(.*?)\n---\s*\n", re.DOTALL)
        meta = {}
        match = FRONTMATTER.match(raw)
        if match:
            try:
                meta = yaml.safe_load(match.group(1)) or {}
            except Exception:
                pass
        self.name = str(meta.get("name") or Path(path).parent.name)
        self.description = str(meta.get("description", ""))[:300]
        self.body = raw[match.end() if match else 0:]

    def __repr__(self):
        return f""

class SkillRegistry:
    def __init__(self, root=REPO_DIR):
        paths = sorted(glob.glob(f"{root}/plugins/vertical-plugins/**/SKILL.md", recursive=True))
        paths += sorted(glob.glob(f"{root}/plugins/**/SKILL.md", recursive=True))
        self.skills = {}
        for p in paths:
            s = Skill(p)
            self.skills.setdefault(s.name.lower(), s)

    def find(self, query):
        query = query.lower()
        hits = [s for k, s in self.skills.items() if query in k]
        if not hits:
            hits = [s for s in self.skills.values() if query in s.description.lower()]
        return hits

    def get(self, query):
        hits = self.find(query)
        if not hits:
            raise KeyError(f"No skill matching '{query}'. Available: {sorted(self.skills)[:40]}")
        return hits
💡
Почему это важно. Разделение метаданных и тела инструкции позволяет модели четко понимать контекст. Описание в YAML используется для поиска, а тело SKILL.md — как строгий алгоритм действий. Это снижает вероятность галлюцинаций.

04Шаг 3: Создание инструментов (Tools) для Python

Модели Claude мощны, но они не умеют считать напрямую. Им нужны инструменты. Мы создаем два ключевых инструмента:

  1. run_python: Позволяет модели выполнить произвольный код Python. Важно: мы используем глобальное пространство имен (_PY_NS), чтобы переменные сохранялись между вызовами. Если агенту нужно посчитать NPV, а затем использовать этот результат для расчета IRR, он может обратиться к переменной из предыдущего шага.
  2. save_file: Позволяет сохранять результаты работы (текст, таблицы, графики) в файлы на диске. Это критично для создания отчетов.
terminalpython
TOOLS = [
    {
        "name": "run_python",
        "description": "Execute Python code and return stdout. pandas as pd and numpy as np are pre-imported. Use print() to return results. State persists across calls.",
        "input_schema": {
            "type": "object",
            "properties": {
                "code": {"type": "string"}
            },
            "required": ["code"]
        }
    },
    {
        "name": "save_file",
        "description": "Save text content to outputs/.",
        "input_schema": {
            "type": "object",
            "properties": {
                "filename": {"type": "string"},
                "content": {"type": "string"}
            },
            "required": ["filename", "content"]
        }
    }
]

_PY_NS = {}

def _tool_run_python(code):
    import numpy as np
    _PY_NS.setdefault("pd", pd)
    _PY_NS.setdefault("np", np)
    buf = io.StringIO()
    try:
        with contextlib.redirect_stdout(buf):
            exec(code, _PY_NS)
        out = buf.getvalue()
        return out[:6000] if out else "(no stdout — use print())"
    except Exception as e:
        return f"ERROR: {type(e).__name__}: {e}"

def _tool_save_file(filename, content):
    safe = os.path.basename(filename)
    path = os.path.join("outputs", safe)
    os.makedirs("outputs", exist_ok=True)
    with open(path, "w", encoding="utf-8") as f:
        f.write(content)
    return f"Saved {path} ({len(content)} chars)"

DISPATCH = {
    "run_python": lambda i: _tool_run_python(i["code"]),
    "save_file": lambda i: _tool_save_file(i["filename"], i["content"])
}

05Шаг 4: Класс SkillAgent и цикл взаимодействия

Сердце системы — класс SkillAgent. При инициализации он принимает запросы на поиск навыков (например, ["dcf"]), находит их в реестре и формирует системный промпт. В этот промпт вставляются описания и тела выбранных навыков.

Метод run реализует классический цикл агента:

  1. Отправляем запрос пользователя в API.
  2. Получаем ответ. Если это текст — это финальный ответ.
  3. Если это вызов инструмента — выполняем его через DISPATCH, добавляем результат в историю сообщений как user и снова отправляем запрос модели.
  4. Повторяем до 12 шагов (чтобы избежать бесконечных циклов).
Создание финансовых AI-агентов на базе Claude: Полный гайд
terminalpython
BASE_SYSTEM = """
You are a financial analyst assistant operating with the skill playbooks provided below (from Anthropic's financial-services repo).
Follow the skill's methodology, conventions, and output format closely.
Use the run_python tool for all numerical work — never do arithmetic in your head.
Use save_file for final deliverables. All work is a DRAFT for human review; do not present it as investment advice.
"""

class SkillAgent:
    def __init__(self, skill_queries, max_skill_chars=12000, verbose=True):
        self.skills = [registry.get(q) for q in skill_queries]
        blocks = []
        for s in self.skills:
            blocks.append(f"\n\n===== SKILL: {s.name} =====\n{s.description}\n{s.body[:max_skill_chars]}")
        self.system = BASE_SYSTEM + "\n".join(blocks)
        self.verbose = verbose

    def run(self, prompt, max_turns=12):
        messages = [{"role": "user", "content": prompt}]
        for turn in range(max_turns):
            resp = client.messages.create(
                model="claude-sonnet-4-6",
                max_tokens=8000,
                system=self.system,
                tools=TOOLS,
                messages=messages
            )
            messages.append({"role": "assistant", "content": resp.content})
            if resp.stop_reason != "tool_use":
                final = "\n".join(b.text for b in resp.content if type(b) == text)
                return final
            
            results = []
            for block in resp.content:
                if block.type == "tool_use":
                    if self.verbose:
                        print(f"  [turn {turn}] tool: {block.name}")
                    out = DISPATCH[block.name](block.input)
                    results.append({
                        "type": "tool_result",
                        "tool_use_id": block.id,
                        "content": str(out)
                    })
            messages.append({"role": "user", "content": results})
        return "(hit max_turns)"
⚠️ Важно
Безопасность и ограничения. В примере используется модель claude-sonnet-4-6. Всегда устанавливайте max_tokens и max_turns, чтобы контролировать расходы и время выполнения. Также помните, что все выходные данные являются черновиками и требуют проверки человеком.

06Практический пример 1: DCF-моделирование и чувствительность

Давайте применим агента к реальной задаче. Мы создаем синтетическую компанию «Meridian Software» с заданными финансовыми показателями. Задача: провести дисконтированный денежный поток (DCF) анализ за 5 лет, рассчитать стоимость компании, стоимость акционерного капитала и implied share price.

Мы передаем агенту навык dcf и инструкцию. Агент сам напишет код для расчета свободных денежных потоков, дисконтирования, терминальной стоимости и построит матрицу чувствительности к WACC и темпам роста.

terminalpython
SAMPLE_CO = """
Target: 'Meridian Software' (synthetic). FY2025 actuals, $mm
Revenue 850 (grew 18% y/y) | EBITDA margin 27% | D&A 4% of rev
CapEx 5% of rev | NWC change 1% of rev growth | Tax rate 24%
Net debt 320 | Diluted shares 92mm
Assumptions: revenue growth fades 18% -> 6% linearly over 5 yrs,
EBITDA margin expands 100bps total, WACC 9.5%, terminal growth 2.5%.
"""

dcf_agent = SkillAgent("dcf")
dcf_answer = dcf_agent.run(f"""
Run a 5-year unlevered DCF per the skill playbook on this company:
{SAMPLE_CO}

Compute enterprise value, equity value, and implied share price with run_python.
Then print a WACC (8.5%-10.5%, 50bp steps) x terminal growth (1.5%-3.5%, 50bp steps) 
sensitivity grid of implied share price as a JSON object under the marker SENS_JSON:,
and give a concise summary.
""")

# Парсинг и визуализация результата
import re
import json
import pandas as pd
import matplotlib.pyplot as plt

match = re.search(r"SENS_JSON:\s*(\{.*\})", dcf_answer, re.DOTALL)
if match:
    grid = json.loads(match.group(1))
    sens = pd.DataFrame(grid)
    sens = sens.apply(pd.to_numeric, errors="coerce")
    
    fig, ax = plt.subplots(figsize=(8, 6))
    im = ax.imshow(sens.values, cmap="RdYlGn", aspect="auto")
    ax.set_xticks(range(len(sens.columns)))
    ax.set_xticklabels(sens.columns)
    ax.set_yticks(range(len(sens.index)))
    ax.set_yticklabels(sens.index)
    ax.set_xlabel("Terminal growth")
    ax.set_ylabel("WACC")
    ax.set_title("Implied share price sensitivity ($)")
    
    for i in range(sens.shape[0]):
        for j in range(sens.shape[1]):
            val = sens.values[i, j]
            if not pd.isna(val):
                ax.text(j, i, f"{val:,.0f}", ha="center", va="center", fontsize=8)
    
    plt.colorbar(im)
    plt.tight_layout()
    plt.show()

Результатом становится не только число, но и наглядная тепловая карта (heatmap), показывающая, как меняется стоимость акции при изменении ключевых допущений. Это именно тот тип визуализации, который ожидается от профессионального финансового аналитика.

07Практический пример 2: Сравнительный анализ (Comps) и Excel

Второй кейс — сравнительный анализ. Мы даем агенту набор компаний-аналогов (Peer Set) с их котировками и финансовыми данными. Задача: рассчитать мультипликаторы (EV/Revenue, EV/EBITDA, P/E) для каждой компании, найти медианное значение и вывести результат в красивый Excel-файл.

Агент использует навык comps. Он генерирует код для расчета EV, формирует DataFrame, а затем использует библиотеку openpyxl для создания файла с двумя листами: таблица компаний и сводная статистика. Кроме того, он применяет стилизацию: жирный шрифт, цвет фона заголовков и автоподбор ширины колонок.

Создание финансовых AI-агентов на базе Claude: Полный гайд
terminalpython
PEERS = """
Synthetic peer set ($mm except per-share):
Ticker  Price  Shares  NetDebt  Rev_NTM  EBITDA_NTM  EPS_NTM
ALFA    64.2   210     450      2900     820         3.10
BRVO    28.7   540     -120     4100     980         1.45
CHRL    112.5  95      760      1850     610         5.60
DLTA    41.9   330     210      2600     700         2.05
"""

comps_agent = SkillAgent("comps")
comps_answer = comps_agent.run(f"""
Per the comps skill, compute EV, EV/Revenue, EV/EBITDA and P/E (all NTM) 
for these peers with run_python:
{PEERS}

Then print the full comps table plus min/25th/median/75th/max summary stats 
as JSON under the marker COMPS_JSON: with keys 'table' (list of row dicts) 
and 'stats' (dict of dicts).
""")

# Сохранение в Excel
match = re.search(r"COMPS_JSON:\s*(\{.*\})", comps_answer, re.DOTALL)
if match:
    payload = json.loads(match.group(1))
    table = pd.DataFrame(payload["table"])
    stats = pd.DataFrame(payload["stats"])
    
    xlsx = "outputs/comps_analysis.xlsx"
    with pd.ExcelWriter(xlsx, engine="openpyxl") as xl:
        table.to_excel(xl, sheet_name="Comps", index=False)
        stats.to_excel(xl, sheet_name="Summary Stats", index=False)
    
    # Стилизация
    from openpyxl import load_workbook
    from openpyxl.styles import Font, PatternFill
    wb = load_workbook(xlsx)
    for ws in wb.worksheets:
        for cell in ws[1]:
            cell.font = Font(bold=True, color="FFFFFF")
            cell.fill = PatternFill("solid", start_color="1F4E79")
        for col in ws.columns:
            max_length = 0
            column_letter = col[0].column_letter
            for cell in col:
                if cell.value is not None:
                    max_length = max(max_length, len(str(cell.value)))
            ws.column_dimensions[column_letter].width = max_length + 2
    wb.save(xlsx)
    print(f"Wrote {xlsx}")
📌 Факт
Масштабируемость. Этот подход позволяет легко добавлять новые навыки. Если у вас есть методология для анализа M&A или LBO, достаточно создать файл SKILL.md с описанием шагов, и агент сразу сможет им пользоваться без изменения кода.

08Практический пример 3: Инвестиционный меморандум (IC Memo)

Финальный шаг — создание документа. Мы используем навык ic-memo для подготовки первого черновика инвестиционного меморандума для выкупа компании Meridian Software. Агент должен использовать данные из предыдущих расчетов (например, оценку в 11x EV/EBITDA) и сформировать структурированный текст: резюме сделки, финансовое обоснование, риски и план выхода.

Агент сохраняет результат в файл ic_memo_meridian.md. Это демонстрирует способность агента не только считать, но и «писать» профессиональные документы, интегрируя данные из разных источников.

09Управляемые агенты и Cookbooks

В репозитории также есть папка managed-agent-cookbooks. Это спецификации для развертывания агентов в более сложных средах, возможно, с использованием оркестраторов. Мы можем инспектировать YAML-файлы, чтобы понять, как эти агенты взаимодействуют друг с другом, как передаются события (events) и как происходит загрузка навыков. Это мост от прототипа в Colab к промышленному развертыванию.

10Что это значит на практике

Разработанная архитектура открывает несколько ключевых возможностей для финансовых профессионалов:

  1. Стандартизация анализа. Все аналитики используют одни и те же методологии, заложенные в SKILL.md. Это исключает ошибки «человеческого фактора» в расчетах и обеспечивает единообразие отчетов.
  2. Ускорение рутины. Расчет мультипликаторов, построение DCF-моделей и подготовка черновиков меморандумов, которые раньше занимали часы, теперь выполняются за минуты. Аналитик тратит время на проверку и интерпретацию, а не на вычисления.
  3. Гибкость. Благодаря модульной структуре, можно легко комбинировать навыки. Например, запустить цепочку: Comps -> DCF -> IC Memo для создания «football field» анализа.
  4. Интеграция с данными. Архитектура готова к подключению MCP-коннекторов (FactSet, Bloomberg, PitchBook). Это означает, что вместо синтетических данных можно использовать реальные рыночные данные в реальном времени.

Для российских специалистов важно отметить, что локальный запуск такого кода не требует доступа к зарубежным облачным сервисам, если вы используете локальные модели или API, доступные в РФ. Однако для работы с Claude потребуется стабильный доступ к интернету и API Anthropic. Альтернативно, логику можно адаптировать под другие LLM, поддерживающие функцию вызова инструментов (function calling).

В заключение, создание skill-driven агентов — это не просто технический эксперимент, а шаг к новой эре финансового консалтинга, где ИИ берет на себя вычислительную и структурную работу, оставляя человеку пространство для стратегических решений и суждений.

Источник: MarkTechPost ↗