Buckets:
| # FinQA Environment | |
| A financial question-answering environment for RL training. Evaluates LLMs on their ability to answer complex financial questions using tool calls on SEC 10-K filing data. | |
| Based on [FinQABenchmark](https://github.com/snorkel-ai/FinQABenchmark) from Snorkel AI. | |
| ## Overview | |
| FinQA tests an agent's ability to: | |
| - Explore available financial tables for a company | |
| - Query table metadata and execute SQL queries | |
| - Perform calculations on extracted data | |
| - Submit final answers to financial questions | |
| **Dataset**: 290 questions from SEC 10-K filings across multiple companies (Alphabet, Amazon, Apple, AT&T, etc.) | |
| **Reward**: Binary (1.0 for correct answer, 0.0 for incorrect) using fuzzy numerical matching with 1% tolerance. | |
| > **Note**: This dataset is for evaluation only. Do not train on it. | |
| ## Quick Start | |
| ### Using Docker | |
| ```bash | |
| # Build the image (from OpenEnv repo root) | |
| docker build -t finqa-env:latest -f envs/finqa_env/server/Dockerfile . | |
| # Run the server | |
| docker run -p 8000:8000 finqa-env:latest | |
| # To run evaluation script (example model gpt-5) | |
| API_BASE_URL=https://api.openai.com/v1 API_KEY=$OPENAI_API_KEY MODEL=gpt-5 python examples/finqa_inference.py | |
| ``` | |
| ### Local Development | |
| ```bash | |
| # Install dependencies | |
| uv pip install pandas | |
| # Download data from HuggingFace | |
| cd envs/finqa_env | |
| ./download_data.sh | |
| ``` | |
| ### Using the Client | |
| The client uses the MCP protocol and is async by default: | |
| ```python | |
| import asyncio | |
| from envs.finqa_env import FinQAEnv, CallToolAction | |
| async def main(): | |
| async with FinQAEnv(base_url="http://localhost:8000") as env: | |
| # Reset to get a question | |
| obs = await env.reset() | |
| question = obs.metadata["question"] | |
| company = obs.metadata["company"] | |
| print(f"Question: {question}") | |
| print(f"Company: {company}") | |
| # Discover available tools | |
| tools = await env.list_tools() | |
| print([t.name for t in tools]) | |
| # Use tools via call_tool (convenience method) | |
| result = await env.call_tool("get_descriptions", company_name=company) | |
| print(f"Available tables: {result}") | |
| # Or use step() with CallToolAction for full observation access | |
| step_result = await env.step(CallToolAction( | |
| tool_name="sql_query", | |
| arguments={ | |
| "company_name": "alphabet", | |
| "table_name": "us_gaap_ScheduleOfIncomeBeforeIncomeTaxDomesticAndForeignTableTextBlock", | |
| "query": "SELECT * FROM data WHERE year = '2022'" | |
| } | |
| )) | |
| print(f"Done: {step_result.done}, Reward: {step_result.reward}") | |
| # Submit answer | |
| result = await env.call_tool("submit_answer", answer="6.118") | |
| asyncio.run(main()) | |
| ``` | |
| ## Available Tools | |
| Tools are auto-discovered via MCP. Use `await env.list_tools()` to see all available tools at runtime. | |
| | Tool | Description | Arguments | | |
| |------|-------------|-----------| | |
| | `get_descriptions` | Get list of available table names for a company | `company_name: str` | | |
| | `get_table_info` | Get table metadata (columns, dtypes, unique values) | `company_name: str, table_name: str` | | |
| | `sql_query` | Execute SQL query on a table (requires filters) | `company_name: str, table_name: str, query: str` | | |
| | `submit_answer` | Submit final answer (ends episode) | `answer: str` | | |
| ### Tool Constraints | |
| - **sql_query**: Must include filters (`WHERE`, `HAVING`, etc.). `SELECT *` is not allowed. | |
| ## Environment Variables | |
| | Variable | Default | Description | | |
| |----------|---------|-------------| | |
| | `FINQA_DATA_PATH` | `/app/env/data` | Path to data directory | | |
| | `FINQA_MAX_STEPS` | `50` | Maximum tool calls per episode | | |
| | `FINQA_TASK` | `finqa` | Task name | | |
| ## Reward Computation | |
| Rewards use fuzzy numerical matching: | |
| - Extracts numbers from `\boxed{...}` format | |
| - Handles percentages, fractions, and decimals | |
| - 1% relative tolerance or 0.01 absolute tolerance | |
| - Returns `1.0` for correct, `0.0` for incorrect | |
| ## Local Development | |
| ```bash | |
| # From OpenEnv repo root | |
| cd envs/finqa_env | |
| # Run server locally | |
| FINQA_DATA_PATH=./data uvicorn server.app:app --reload --port 8000 | |
| # Test with curl | |
| curl http://localhost:8000/health | |
| curl -X POST http://localhost:8000/reset | |
| ``` | |
| ## Integration with RL Frameworks | |
| ### TRL (GRPO) | |
| ```python | |
| import asyncio | |
| from trl import GRPOTrainer | |
| from envs.finqa_env import FinQAEnv | |
| async def rollout_func(prompts, trainer): | |
| async with FinQAEnv(base_url="http://localhost:8000") as env: | |
| obs = await env.reset() | |
| # Your agent logic here using await env.call_tool(...) | |
| return {"reward": obs.reward, "completion": completion} | |
| trainer = GRPOTrainer( | |
| model=model, | |
| rollout_func=rollout_func, | |
| ... | |
| ) | |
| ``` | |
| ## Project Structure | |
| ``` | |
| finqa_env/ | |
| ├── __init__.py # Exports FinQAEnv, CallToolAction, ListToolsAction | |
| ├── models.py # FinQAState and tool name constants | |
| ├── client.py # MCP client (subclasses MCPToolClient) | |
| ├── pyproject.toml # Dependencies | |
| ├── README.md # This file | |
| ├── data/ # Benchmark data (run download_data.sh) | |
| │ ├── benchmark_questions/ | |
| │ │ └── finqa.csv | |
| │ └── input_companies/ | |
| │ └── [company folders] | |
| ├── download_data.sh # Downloads data from HuggingFace | |
| └── server/ | |
| ├── __init__.py | |
| ├── finqa_environment.py # MCPEnvironment subclass with @mcp.tool decorators | |
| ├── tools.py # Tool implementations | |
| ├── rewards.py # Reward computation | |
| ├── app.py # FastAPI server | |
| └── Dockerfile | |
| ``` | |
| ## References | |
| - [HuggingFace Dataset](https://huggingface.co/datasets/snorkelai/agent-finance-reasoning) | |
| - [Leaderboard](https://leaderboard.snorkel.ai/category/snorkelfinance) | |
Xet Storage Details
- Size:
- 5.86 kB
- Xet hash:
- 19cb0e88331be0ae7a8f110953e955a02683acdea4354094713a7c5f378dae9d
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.