The simplest check is:
 if "key_2" in my_dict.get("key_1", ()):
where get never raises a KeyError; when the key is missing, it returns the default value provided, an empty tuple, which "key_2" will never be in (the choice of the empty tuple over the empty dict is a minor efficiency boost; Python would have to reconstruct the empty dict for each call, but it can reuse the singleton tuple over and over without building new ones).
While it's more verbose, the other approach to this is the EAFP approach; lookup the values assuming they exist, if you end up receiving a KeyError, it means one was missing:
try:
    my_dict["key_1"]["key_2"]  # If the value will be needed, assign to name here, use name in else:
except KeyError:
    func_2()  # One of the lookups failed, call func_2
else:
    func_1()  # Lookup succeeded, both keys exist, call func_1
Obviously:
if "key_1" in my_dict and "key_2" in my_dict["key_1"]:
    func_1()
else:
    func_2()
is also an option, but it requires looking up "key_1" twice, and is relatively verbose (that said, it is straightforward; it's not an awful solution, I just enjoy being needlessly clever).